Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions libraries/localization/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Localization API

The Localization API provides a consistent access point for localized text, and adds support for localization in versions that do not natively do so.

## Localizing Text

The `L10n` class provides utilities for localizing text.

```java
# localizing a translation key
String localizedText = L10n.get("example.translationKey");

# localizing a translation key with formatting arguments
String localizedTextWithArgs = L10n.get("example.translationKey", "Some Arg", 1);

# localizing a translation key with a default value in case no localization exists
String localizedTextOrDefault = L10n.getOrDefault("example.translationKey", "Example Text");

# checking whether a localization for a translation key exists
boolean localizedTextExists = L10n.has("example.translationKey");
```

## Providing Translations

Translation files can be added to your mod's resources and will be loaded automatically. While Minecraft natively only supports `.lang` files in versions 18w01a and below, and only `.json` files in 18w02a and above, the Localization API ensures both `.lang` and `.json` files are supported in any Minecraft version.

The Localization API also adds support for all-lowercase translation file names in 1.10.2 and below (e.g. `en_us.lang` instead of `en_US.lang`).

## Localization in Minecraft Alpha

Minecraft started localizing text elements in Minecraft Beta. The Localization API adds support for localization in Minecraft Alpha. Do note that no in-game text is modified in any version of the game, making this mostly a feature for modders to take advantage of.
5 changes: 5 additions & 0 deletions libraries/localization/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
setUpLibrary(project)

dependencies {
implementation 'com.google.code.gson:gson:2.8.0'
}
6 changes: 6 additions & 0 deletions libraries/localization/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
library_id = localization
library_name = Localization
library_description = Localization API and events.
library_version = 0.1.0-alpha.1

osl_dependencies = core:>=0.7.0,entrypoints:>=0.5.0,executors:>=0.1.0,text-components:>=0.1.0-,resource-loader:>=0.7.0-
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
setUpModule(project)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
min_mc_version = 11w49a
max_mc_version = 1.5.2
minecraft_dependency = >=1.1-alpha.11.49.a <=1.5.2

minecraft_version = 1.5.2
client_nests_build = 6

entrypoint_client_init = net.ornithemc.osl.localization.impl.LanguageReloader::init
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package net.ornithemc.osl.localization.impl;

import net.ornithemc.osl.resource.loader.api.client.ClientResourceLoaderEvents;
import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager;
import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReloadListener;

public class LanguageReloader implements ResourceReloadListener {

public static void init() {
ClientResourceLoaderEvents.INIT_RESOURCE_MANAGER.register(resourceManager -> {
resourceManager.addReloader(new LanguageReloader());
});
ClientResourceLoaderEvents.START_RESOURCE_RELOAD.register((resourceManager, context) -> {
Localization.getLanguageManager().reload(context.resourcePacks());
});
}

@Override
public void resourcesReloaded(ResourceManager resourceManager) {
Localization.getLanguageManager().reloadLocale(resourceManager);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package net.ornithemc.osl.localization.impl.mixin.client;

import java.util.Properties;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;

import net.minecraft.locale.Language;

@Mixin(Language.class)
public interface LanguageAccess {

@Accessor("translations")
Properties accessTranslations();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package net.ornithemc.osl.localization.impl.mixin.client;

import java.util.Properties;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;

import net.minecraft.locale.Language;

import net.ornithemc.osl.localization.impl.Localization;
import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager;

@Mixin(Language.class)
public class LanguageMixin {

@Shadow
private static Language INSTANCE;

@Shadow
private Properties translations;
@Shadow
private String currentCode;

@Inject(
method = "<clinit>",
at = @At(
value = "TAIL"
)
)
private static void osl$localization$initLocale(CallbackInfo ci) {
Localization.getLocale().wrap(((LanguageAccess) INSTANCE).accessTranslations());
}

@Inject(
method = "load",
at = @At(
value = "TAIL"
)
)
private void osl$localization$reloadLanguageManager(CallbackInfo ci) {
// each ServerPlayerEntity also holds an instance of this class
if ((Language) (Object) this == INSTANCE) {
Localization.reloadLanguageManager();
}
}

@Inject(
method = "loadLanguage",
at = @At(
value = "HEAD"
)
)
private void osl$localization$setLanguage(CallbackInfo ci) {
// each ServerPlayerEntity also holds an instance of this class
if ((Language) (Object) this == INSTANCE) {
Localization.getLanguageManager().setSelectedLanguage(this.currentCode);
}
}

@Inject(
method = "loadLanguage",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/locale/Language;loadTranslations(Ljava/util/Properties;Ljava/lang/String;)V"
)
)
private void osl$localization$wrapTranslations(CallbackInfo ci, @Local String language, @Local Properties translations) {
// each ServerPlayerEntity also holds an instance of this class
if ((Language) (Object) this == INSTANCE) {
// the translations map is replaced with each reload
Localization.getLocale().wrap(translations);
}
}

@WrapOperation(
method = "loadLanguage",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/locale/Language;loadTranslations(Ljava/util/Properties;Ljava/lang/String;)V"
)
)
private void osl$localization$loadExtraTranslations(Language self, Properties translations, String language, Operation<Void> op) {
// each ServerPlayerEntity also holds an instance of this class
if ((Language) (Object) this == INSTANCE) {
Localization.getLocale().loadLanguage(ResourceManager.client(), language);
}

// no need to run the original operation
// op.call(self, translations, language);
}

@Inject(
method = "loadLanguage",
at = @At(
value = "TAIL"
)
)
private void osl$localization$localeReloaded(CallbackInfo ci) {
// each ServerPlayerEntity also holds an instance of this class
if ((Language) (Object) this == INSTANCE) {
Localization.getLocale().setLastUpdateTime();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"schemaVersion": 1,
"id": "osl-localization",
"version": "0.1.0-alpha.1+mc11w49a-mc1.5.2",
"environment": "*",
"entrypoints": {
"client-init": [
"net.ornithemc.osl.localization.impl.LanguageReloader::init"
]
},
"mixins": [
"osl.localization.mixins.json"
],
"depends": {
"fabricloader": "\u003e\u003d0.18.0",
"minecraft": "\u003e\u003d1.1-alpha.11.49.a \u003c\u003d1.5.2",
"osl-core": "\u003e\u003d0.7.0",
"osl-entrypoints": "\u003e\u003d0.5.0",
"osl-executors": "\u003e\u003d0.1.0",
"osl-text-components": "\u003e\u003d0.1.0-",
"osl-resource-loader": "\u003e\u003d0.7.0-"
},
"name": "OSL Localization",
"description": "Localization API and events.",
"authors": [
"OrnitheMC"
],
"contact": {
"homepage": "https://ornithemc.net/",
"issues": "https://github.com/OrnitheMC/ornithe-standard-libraries/issues",
"sources": "https://github.com/OrnitheMC/ornithe-standard-libraries"
},
"license": "Apache-2.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"required": true,
"minVersion": "0.8",
"package": "net.ornithemc.osl.localization.impl.mixin",
"compatibilityLevel": "JAVA_8",
"mixins": [
],
"client": [
"client.LanguageAccess",
"client.LanguageMixin"
],
"server": [
],
"injectors": {
"defaultRequire": 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
setUpModule(project)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
min_mc_version = 13w26a
max_mc_version = 18w01a
minecraft_dependency = >=1.6-alpha.13.26.a <=1.13-alpha.18.1.a

minecraft_version = 1.8.2-pre4
raven_build = 1
sparrow_build = 1
nests_build = 3
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package net.ornithemc.osl.localization.impl.access;

import net.ornithemc.osl.core.api.util.NamespacedIdentifier;

public interface SimpleResourceAccess {

NamespacedIdentifier osl$localization$getLocation();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package net.ornithemc.osl.localization.impl.mixin.client;

import java.util.Map;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import net.minecraft.client.resource.language.LanguageManager;

import net.ornithemc.osl.localization.api.language.Language;
import net.ornithemc.osl.localization.impl.Localization;

@Mixin(LanguageManager.class)
public class LanguageManagerMixin {

@Shadow
private Map<String, Language> languages;

@Shadow
private String currentCode;

@Inject(
method = "<init>",
at = @At(
value = "TAIL"
)
)
private void osl$localization$initLanguageManager(CallbackInfo ci) {
Localization.getLanguageManager().wrap(this.languages, net.minecraft.client.resource.language.Language::new);
}

@Inject(
method = "setLanguage",
at = @At(
value = "TAIL"
)
)
private void osl$localization$setLanguage(CallbackInfo ci) {
Localization.getLanguageManager().setSelectedLanguage(this.currentCode);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package net.ornithemc.osl.localization.impl.mixin.client;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

import net.ornithemc.osl.localization.api.language.Language;

@Mixin(net.minecraft.client.resource.language.Language.class)
public class LanguageMixin implements Language {

@Shadow
private String code;
@Shadow
private String region;
@Shadow
private String name;
@Shadow
private boolean bidirectional;

@Override
public String code() {
return this.code;
}

@Override
public String name() {
return this.name;
}

@Override
public String region() {
return this.region;
}

@Override
public boolean bidirectional() {
return this.bidirectional;
}
}
Loading
Loading