mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 20:28:00 +00:00
Implement better in-game localization/translation
This commit is contained in:
@@ -1,17 +1,20 @@
|
||||
package forge.util;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
public class CardTranslation {
|
||||
|
||||
private static Map <String, String> translatednames;
|
||||
private static Map <String, String> translatedtypes;
|
||||
private static Map <String, String> translatedoracles;
|
||||
private static Map <String, List <Pair <String, String> > > oracleMappings;
|
||||
private static Map <String, String> translatedCaches;
|
||||
private static String languageSelected = "en-US";
|
||||
|
||||
private static void readTranslationFile(String language, String languagesDirectory) {
|
||||
@@ -27,7 +30,7 @@ public class CardTranslation {
|
||||
translatedtypes.put(matches[0], matches[2]);
|
||||
}
|
||||
if (matches.length >= 4) {
|
||||
translatedoracles.put(matches[0], matches[3].replace("\\n", "\n\n"));
|
||||
translatedoracles.put(matches[0], matches[3].replace("\\n", "\r\n\r\n"));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@@ -89,7 +92,101 @@ public class CardTranslation {
|
||||
translatednames = new HashMap<>();
|
||||
translatedtypes = new HashMap<>();
|
||||
translatedoracles = new HashMap<>();
|
||||
oracleMappings = new HashMap<>();
|
||||
translatedCaches = new HashMap<>();
|
||||
readTranslationFile(languageSelected, languagesDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String replaceCardName(String language, String name, String toracle) {
|
||||
String nickName = language.equals("en-US") ? Lang.getEnglishInstance().getNickName(name) : Lang.getInstance().getNickName(name);
|
||||
String result = TextUtil.fastReplace(toracle, name, "CARDNAME");
|
||||
if (!nickName.equals(name)) {
|
||||
result = TextUtil.fastReplace(result, nickName, "NICKNAME");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void buildOracleMapping(String faceName, String oracleText) {
|
||||
if (!needsTranslation() || oracleMappings.containsKey(faceName)) return;
|
||||
String translatedName = getTranslatedName(faceName);
|
||||
String translatedText = getTranslatedOracle(faceName);
|
||||
List <Pair <String, String> > mapping = new ArrayList<>();
|
||||
String [] splitOracleText = oracleText.split("\\\\n");
|
||||
String [] splitTranslatedText = translatedText.split("\r\n\r\n");
|
||||
|
||||
for (int i = 0; i < splitOracleText.length && i < splitTranslatedText.length; i++) {
|
||||
String toracle = replaceCardName("en-US", faceName, splitOracleText[i]);
|
||||
String ttranslated = replaceCardName(languageSelected, translatedName, splitTranslatedText[i]);
|
||||
// Remove reminder text in English oracle text unless entire line is reminder text
|
||||
if (!toracle.startsWith("(")) {
|
||||
toracle = toracle.replaceAll("\\(.*\\)", "");
|
||||
}
|
||||
mapping.add(Pair.of(toracle, ttranslated));
|
||||
}
|
||||
oracleMappings.put(faceName, mapping);
|
||||
}
|
||||
|
||||
public static String translateMultipleDescriptionText(String descText, String cardName) {
|
||||
if (!needsTranslation()) return descText;
|
||||
String [] splitDescText = descText.split("\r\n");
|
||||
String result = descText;
|
||||
for (String text : splitDescText) {
|
||||
if (text.isEmpty()) continue;
|
||||
String translated = translateSingleDescriptionText(text, cardName);
|
||||
if (!text.equals(translated)) {
|
||||
result = TextUtil.fastReplace(result, text, translated);
|
||||
} else {
|
||||
// keywords maybe combined into one line, split them and try translate again
|
||||
String [] splitKeywords = text.split(", ");
|
||||
if (splitKeywords.length <= 1) continue;
|
||||
for (String keyword : splitKeywords) {
|
||||
if (keyword.contains(" ")) continue;
|
||||
translated = translateSingleDescriptionText(keyword, cardName);
|
||||
if (!keyword.equals(translated)) {
|
||||
result = TextUtil.fastReplace(result, keyword, translated);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String translateSingleDescriptionText(String descText, String cardName) {
|
||||
if (!needsTranslation()) return descText;
|
||||
if (translatedCaches.containsKey(descText)) return translatedCaches.get(descText);
|
||||
|
||||
List <Pair <String, String> > mapping = oracleMappings.get(cardName);
|
||||
if (mapping == null) return descText;
|
||||
String result = descText;
|
||||
if (!mapping.isEmpty()) {
|
||||
result = translateSingleIngameText(descText, mapping);
|
||||
}
|
||||
translatedCaches.put(descText, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String translateSingleIngameText(String descText, List <Pair <String, String> > mapping) {
|
||||
String tcompare = descText.startsWith("(") ? descText : descText.replaceAll("\\(.*\\)", "");
|
||||
|
||||
// Use Levenshtein Distance to find matching oracle text and replace it with translated text
|
||||
int candidateIndex = mapping.size();
|
||||
int minDistance = tcompare.length();
|
||||
for (int i = 0; i < mapping.size(); i++) {
|
||||
String toracle = mapping.get(i).getLeft();
|
||||
int threshold = Math.min(toracle.length(), tcompare.length()) / 3;
|
||||
int distance = StringUtils.getLevenshteinDistance(toracle, tcompare, threshold);
|
||||
if (distance != -1 && distance < minDistance) {
|
||||
minDistance = distance;
|
||||
candidateIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (candidateIndex < mapping.size()) {
|
||||
return mapping.get(candidateIndex).getRight();
|
||||
}
|
||||
|
||||
return descText;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.google.common.collect.Lists;
|
||||
public abstract class Lang {
|
||||
|
||||
private static Lang instance;
|
||||
private static Lang englishInstance;
|
||||
|
||||
protected String languageCode;
|
||||
protected String countryCode;
|
||||
@@ -41,11 +42,20 @@ public abstract class Lang {
|
||||
}
|
||||
instance.languageCode = language;
|
||||
instance.countryCode = country;
|
||||
|
||||
// Create english instance for internal usage
|
||||
englishInstance = new LangEnglish();
|
||||
englishInstance.languageCode = "en";
|
||||
englishInstance.countryCode = "US";
|
||||
}
|
||||
|
||||
public static Lang getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static Lang getEnglishInstance() {
|
||||
return englishInstance;
|
||||
}
|
||||
|
||||
protected Lang() {
|
||||
}
|
||||
@@ -170,4 +180,6 @@ public abstract class Lang {
|
||||
}
|
||||
return Integer.toString(n);
|
||||
}
|
||||
|
||||
public abstract String getNickName(final String name);
|
||||
}
|
||||
|
||||
@@ -19,4 +19,9 @@ public class LangChinese extends Lang {
|
||||
return getPossesive(owner) + object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNickName(final String name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,4 +30,8 @@ public class LangEnglish extends Lang {
|
||||
return getPossesive(owner) + " " + object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNickName(final String name) {
|
||||
return name.split(", ")[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,4 +26,10 @@ public class LangGerman extends Lang {
|
||||
return getPossesive(owner) + " " + object;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getNickName(final String name) {
|
||||
return name.split(", ")[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,4 +23,9 @@ public class LangItalian extends Lang {
|
||||
return getPossesive(owner) + " " + object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNickName(final String name) {
|
||||
return name.split(", ")[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,4 +19,11 @@ public class LangJapanese extends Lang {
|
||||
return getPossesive(owner) + object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNickName(final String name) {
|
||||
String [] splitName = name.split("、");
|
||||
if (splitName.length > 1) return splitName[1];
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,4 +23,9 @@ public class LangSpanish extends Lang {
|
||||
return getPossesive(owner) + " " + object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNickName(final String name) {
|
||||
return name.split(", ")[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user