Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Common] Add support for custom language files #191

Merged
merged 5 commits into from
Jan 5, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Setup Gradle
uses: gradle/[email protected]
with:
gradle-version: 8.1.1
gradle-version: 8.4
- name: Build TASmod with Gradle
run: gradle build
- name: Upload Test Report
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/buildandupload.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: Setup Gradle
uses: gradle/[email protected]
with:
gradle-version: 8.1.1
gradle-version: 8.4
- name: Build TASmod with Gradle
run: gradle build
- name: Upload artifact
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ out
# gradle
build
.gradle
gradle
gradlew
gradlew.bat

# other
eclipse
Expand Down
3 changes: 1 addition & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ configurations {
// dependencies
dependencies {
// tasmod dependencies
embed group: 'com.dselent', name: 'bigarraylist', version: '1.0'

embed group: 'com.dselent', name: 'bigarraylist', version: '1.1'
compileOnly group: 'com.minecrafttas', name: 'killtherng', version: '2.0'
downloadMod group: 'com.minecrafttas', name: 'killtherng-full', version: '2.0' // for downloadKTRNG task

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ [email protected]
# TASmod properties
group=com.minecrafttas
artifact=TASmod-1.12.2
version=Beta1-SNAPHOT
version=Beta1-SNAPSHOT
115 changes: 115 additions & 0 deletions src/main/java/com/minecrafttas/mctcommon/LanguageManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package com.minecrafttas.common;

import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.gson.Gson;
import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.util.ResourceLocation;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Pattern;

public class LanguageManager {

private static Set<String> modids = new HashSet<>();
private static final Splitter SPLITTER = Splitter.on('=').limit(2);
private static final Pattern PATTERN = Pattern.compile("%(\\d+\\$)?[\\d\\.]*[df]");

public static void onResourceManagerReload(Map<String, String> original, IResourceManager iResourceManager, List<String> languageList) {
for (String language : languageList) { // Go through all loaded languages
language = language.toLowerCase(); // Set everything to lowercase which prevents headaches in 1.10.2 and below
for (String modid : modids) { // Iterate through all registered modids
HashMap<String, String> newTranslations = new HashMap<>();
if (iResourceManager.getResourceDomains().contains(modid)) {
try {
newTranslations = getFromResourcePack(iResourceManager, modid, language); // Load .json translations from resource pack
} catch (IOException var9) {
}
}
if (newTranslations.isEmpty()) {
try {
newTranslations = loadLang(getFromResources(modid, language, "lang")); // Load .lang files from resources
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (newTranslations.isEmpty()) {
newTranslations = loadJson(getFromResources(modid, language, "json")); // Load .json translations from resources
}
/**
* Making this put if absent here creates the following hirarchy:
* Resourcepack .lang beats
* Resourcepack .json beats
* Resources .lang beats
* Resources .json
*
* Lang is preferred over json and resourcepacks are preferred over json
*/
newTranslations.forEach(original::putIfAbsent);
}
}
}

private static InputStream getFromResources(String resourceDomain, String language, String fileending) {
return LanguageManager.class.getResourceAsStream(String.format("/assets/%s/lang/%s.%s", resourceDomain, language, fileending));
}

private static HashMap<String, String> getFromResourcePack(IResourceManager iResourceManager, String resourceDomain, String language) throws IOException {
String languageFile = String.format("lang/%s.json", language);
HashMap<String, String> out = new HashMap<>();
Collection<IResource> allResources = iResourceManager.getAllResources(new ResourceLocation(resourceDomain, languageFile));
for (IResource iResource : allResources) {
InputStream inputStream = iResource.getInputStream();
out.putAll(loadJson(inputStream));
}
return out;
}

/**
* Registers your mod to be processed by the language manager<br>
* This will allow you to add .json and/or .lang files to assets/modid/lang<br>
* with en_us.lang/en_us.json (<strong>lowercase!</strong>)
*
* @param modid The modid of your mod
*/
public static void registerMod(String modid) {
modids.add(modid);
}

private static HashMap<String, String> loadJson(InputStream inputStream) {
if (inputStream == null) {
return new HashMap<String, String>();
}
Gson gson = new Gson();
HashMap<String, String> template = new HashMap<>();
HashMap<String, String> out = (HashMap<String, String>) gson.fromJson(new InputStreamReader(inputStream), template.getClass());
out.forEach((key, value) -> {
value = PATTERN.matcher(value).replaceAll("%$1s");
});
return out;
}

private static HashMap<String, String> loadLang(InputStream inputStream) throws IOException {
HashMap<String, String> out = new HashMap<>();
if (inputStream == null) {
return out;
}
for (String string : IOUtils.readLines(inputStream, StandardCharsets.UTF_8)) {
if (!string.isEmpty() && string.charAt(0) != '#') {
String[] key_value_pair = Iterables.toArray(SPLITTER.split(string), String.class);
if (key_value_pair != null && key_value_pair.length == 2) {
String key = key_value_pair[0];
String value = PATTERN.matcher(key_value_pair[1]).replaceAll("%$1s");
out.put(key, value);
}
}
}
return out;
}
}
24 changes: 24 additions & 0 deletions src/main/java/com/minecrafttas/mctcommon/mixin/MixinLocale.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.minecrafttas.common.mixin;

import com.minecrafttas.common.LanguageManager;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.Locale;
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 java.util.List;
import java.util.Map;

@Mixin(Locale.class)
public class MixinLocale {

@Shadow
private Map<String, String> properties;
@Inject(method="loadLocaleDataFiles", at = @At("RETURN"))
private void inject_loadLocalDataFiles(IResourceManager iResourceManager, List<String> list, CallbackInfo ci){
LanguageManager.onResourceManagerReload(properties, iResourceManager, list);
}
}
23 changes: 12 additions & 11 deletions src/main/java/com/minecrafttas/tasmod/TASmodClient.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
package com.minecrafttas.tasmod;

import static com.minecrafttas.tasmod.TASmod.LOGGER;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.logging.log4j.Level;
import org.lwjgl.input.Keyboard;

import com.minecrafttas.common.LanguageManager;
import com.minecrafttas.mctcommon.Configuration;
import com.minecrafttas.mctcommon.Configuration.ConfigOptions;
import com.minecrafttas.mctcommon.KeybindManager;
Expand Down Expand Up @@ -37,7 +28,6 @@
import com.minecrafttas.tasmod.util.ShieldDownloader;
import com.minecrafttas.tasmod.virtual.VirtualInput;
import com.minecrafttas.tasmod.virtual.VirtualKeybindings;

import net.fabricmc.api.ClientModInitializer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
Expand All @@ -47,6 +37,15 @@
import net.minecraft.client.multiplayer.ServerData;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.server.MinecraftServer;
import org.apache.logging.log4j.Level;
import org.lwjgl.input.Keyboard;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import static com.minecrafttas.tasmod.TASmod.LOGGER;

public class TASmodClient implements ClientModInitializer, EventClientInit, EventPlayerJoinedClientSide, EventOpenGui{

Expand Down Expand Up @@ -111,6 +110,8 @@ public void onInitializeClient() {
}
config = new Configuration("TASmod configuration", new File(configDir, "tasmod.cfg"));

LanguageManager.registerMod("tasmod");

// Execute /restartandplay. Load the file to start from the config. If it exists load the playback file on start.
String fileOnStart = config.get(ConfigOptions.FileToOpen);
if (fileOnStart.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.google.common.collect.ImmutableList;
import com.minecrafttas.tasmod.TASmod;

import net.minecraft.client.resources.I18n;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
Expand All @@ -29,7 +30,7 @@ public List<String> getAliases() {

@Override
public String getUsage(ICommandSender sender) {
return "/tickrate <ticks per second>";
return I18n.format("tickratechanger.tasmod.command.usage"); // "/tickrate <ticks per second>"
}

@Override
Expand All @@ -40,7 +41,7 @@ public int getRequiredPermissionLevel() {
@Override
public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException {
if (args.length == 0) {
sender.sendMessage(new TextComponentString("Current tickrate: " + TASmod.tickratechanger.ticksPerSecond));
sender.sendMessage(new TextComponentString( I18n.format("tickratechanger.tasmod.command.show", TASmod.tickratechanger.ticksPerSecond))); //"Current tickrate: "
return;
}
float tickrate;
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/assets/tasmod/lang/en_us.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"tickratechanger.tasmod.command.show": "Current tickrate: %s",
"tickratechanger.tasmod.command.usage": "/tickrate <ticks per second>"
}
3 changes: 2 additions & 1 deletion src/main/resources/mctcommon.mixin.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"MixinMinecraft",
"MixinNetHandlerPlayClient",
"MixinWorldClient",
"MixinEntityRenderer"
"MixinEntityRenderer",
"MixinLocale"
]
}