Skip to content

Commit

Permalink
Initial localization support
Browse files Browse the repository at this point in the history
  • Loading branch information
NebelNidas committed Oct 16, 2023
1 parent 6e7de77 commit 7386425
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 12 deletions.
35 changes: 23 additions & 12 deletions src/main/java/net/fabricmc/mappingio/format/MappingFormat.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@

package net.fabricmc.mappingio.format;

import java.util.Locale;

import net.fabricmc.mappingio.i18n.I18n;
import net.fabricmc.mappingio.i18n.MioLocale;

/**
* Represents a supported mapping format. Feature comparison table:
* <table>
Expand Down Expand Up @@ -98,55 +103,59 @@ public enum MappingFormat {
/**
* The {@code Tiny} mapping format, as specified <a href="https://fabricmc.net/wiki/documentation:tiny">here</a>.
*/
TINY_FILE("Tiny file", "tiny", true, true, false, false, false),
TINY_FILE("tiny", true, true, false, false, false),

/**
* The {@code Tiny v2} mapping format, as specified <a href="https://fabricmc.net/wiki/documentation:tiny2">here</a>.
*/
TINY_2_FILE("Tiny v2 file", "tiny", true, true, true, true, true),
TINY_2_FILE("tiny", true, true, true, true, true),

/**
* Enigma's mapping format, as specified <a href="https://fabricmc.net/wiki/documentation:enigma_mappings">here</a>.
*/
ENIGMA_FILE("Enigma file", "mapping", false, true, true, true, false),
ENIGMA_FILE("mapping", false, true, true, true, false),

/**
* Enigma's mapping format (in directory form), as specified <a href="https://fabricmc.net/wiki/documentation:enigma_mappings">here</a>.
*/
ENIGMA_DIR("Enigma directory", null, false, true, true, true, false),
ENIGMA_DIR(null, false, true, true, true, false),

/**
* The {@code SRG} ({@code Searge RetroGuard}) mapping format, as specified <a href="https://github.com/MinecraftForge/SrgUtils/blob/67f30647ece29f18256ca89a23cda6216d6bd21e/src/main/java/net/minecraftforge/srgutils/InternalUtils.java#L69-L81">here</a>.
*/
SRG_FILE("SRG file", "srg", false, false, false, false, false),
SRG_FILE("srg", false, false, false, false, false),

/**
* The {@code TSRG} ({@code Tiny SRG}, since it saves disk space over SRG) mapping format, as specified <a href="https://github.com/MinecraftForge/SrgUtils/blob/67f30647ece29f18256ca89a23cda6216d6bd21e/src/main/java/net/minecraftforge/srgutils/InternalUtils.java#L196-L213">here</a>.
*/
TSRG_FILE("TSRG file", "tsrg", false, false, false, false, false),
TSRG_FILE("tsrg", false, false, false, false, false),

/**
* The {@code TSRG v2} mapping format, as specified <a href="https://github.com/MinecraftForge/SrgUtils/blob/67f30647ece29f18256ca89a23cda6216d6bd21e/src/main/java/net/minecraftforge/srgutils/InternalUtils.java#L262-L285">here</a>.
*/
TSRG_2_FILE("TSRG2 file", "tsrg", true, true, false, true, false),
TSRG_2_FILE("tsrg", true, true, false, true, false),

/**
* ProGuard's mapping format, as specified <a href="https://www.guardsquare.com/manual/tools/retrace">here</a>.
*/
PROGUARD_FILE("ProGuard file", "txt", false, true, false, false, false);
PROGUARD_FILE("txt", false, true, false, false, false);

MappingFormat(String name, String fileExt,
boolean hasNamespaces, boolean hasFieldDescriptors,
MappingFormat(String fileExt, boolean hasNamespaces, boolean hasFieldDescriptors,
boolean supportsComments, boolean supportsArgs, boolean supportsLocals) {
this.name = name;
this.fileExt = fileExt;
this.translationKey = "format." + name().toLowerCase(Locale.ROOT);
this.name = getName(MioLocale.EN_US);
this.hasNamespaces = hasNamespaces;
this.hasFieldDescriptors = hasFieldDescriptors;
this.supportsComments = supportsComments;
this.supportsArgs = supportsArgs;
this.supportsLocals = supportsLocals;
}

public String getName(MioLocale locale) {
return I18n.translate(translationKey, locale);
}

public boolean hasSingleFile() {
return fileExt != null;
}
Expand All @@ -157,11 +166,13 @@ public String getGlobPattern() {
return "*."+fileExt;
}

public final String name;
public final String fileExt;
/** @deprecated Use {@link #getName()} instead. */
public final String name;
public final boolean hasNamespaces;
public final boolean hasFieldDescriptors;
public final boolean supportsComments;
public final boolean supportsArgs;
public final boolean supportsLocals;
private final String translationKey;
}
76 changes: 76 additions & 0 deletions src/main/java/net/fabricmc/mappingio/i18n/I18n.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright (c) 2023 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.fabricmc.mappingio.i18n;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;

import org.jetbrains.annotations.ApiStatus;

@ApiStatus.Internal
public class I18n {
private I18n() {
}

public static String translate(String key, MioLocale locale, Object... args) {
return String.format(translate(key, locale), args);
}

public static String translate(String key, MioLocale locale) {
try {
return messageBundles.getOrDefault(locale, load(locale)).getString(key);
} catch (Exception e) {
System.err.println("Exception while translating key " + key + " to locale " + locale.id + ": " + e.getMessage());
if (locale == fallbackLocale) return key;

try {
return messageBundles.getOrDefault(fallbackLocale, load(fallbackLocale)).getString(key);
} catch (Exception e2) {
System.err.println("Exception while translating key " + key + " to fallback locale: " + e2.getMessage());
return key;
}
}
}

private static ResourceBundle load(MioLocale locale) {
ResourceBundle resBundle;
String resName = String.format("/i18n/%s.properties", locale.id);
URL resUrl = I18n.class.getResource(resName);

if (resUrl == null) {
throw new RuntimeException("Locale resource not found: " + resName);
}

try (Reader reader = new InputStreamReader(resUrl.openStream(), StandardCharsets.UTF_8)) {
resBundle = new PropertyResourceBundle(reader);
messageBundles.put(locale, resBundle);
return resBundle;
} catch (IOException e) {
throw new RuntimeException("Failed to load " + resName, e);
}
}

private static final MioLocale fallbackLocale = MioLocale.EN_US;
private static final Map<MioLocale, ResourceBundle> messageBundles = new HashMap<>();
}
27 changes: 27 additions & 0 deletions src/main/java/net/fabricmc/mappingio/i18n/MioLocale.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2023 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.fabricmc.mappingio.i18n;

public enum MioLocale {
EN_US("en_us");

MioLocale(String id) {
this.id = id;
}

final String id;
}
9 changes: 9 additions & 0 deletions src/main/resources/i18n/en_us.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
format.tiny_file = Tiny File
format.tiny_2_file = Tiny v2 File
format.enigma_file = Enigma File
format.enigma_dir = Enigma Directory
format.mcp_dir = MCP Directory
format.srg_file = SRG File
format.tsrg_file = TSRG File
format.tsrg_2_file = TSRG2 File
format.proguard_file = ProGuard File
43 changes: 43 additions & 0 deletions src/test/java/net/fabricmc/mappingio/i18n/I18nTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2023 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.fabricmc.mappingio.i18n;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.Test;

import net.fabricmc.mappingio.format.MappingFormat;

public class I18nTest {
@Test
public void mappingFormats() {
for (MappingFormat format : MappingFormat.values()) {
String enUsName = format.getName(MioLocale.EN_US);
assertTrue(format.name.equals(enUsName));

for (MioLocale locale : MioLocale.values()) {
String translatedName = format.getName(locale);
assertFalse(translatedName.startsWith("format."));

if (locale != MioLocale.EN_US) {
assertFalse(translatedName.equals(enUsName));
}
}
}
}
}

0 comments on commit 7386425

Please sign in to comment.