Merge branch 'ingame_translation' into 'master'

Better in-game localization/translation of oracle texts

See merge request core-developers/forge!4007
This commit is contained in:
Michael Kamensky
2021-02-25 13:34:35 +00:00
25 changed files with 233 additions and 119 deletions

View File

@@ -87,7 +87,7 @@ public abstract class SpellAbilityEffect {
// by typing "SpellDescription" they want to bypass the Effect's string builder
if ("SpellDescription".equalsIgnoreCase(stackDesc)) {
if (params.get("SpellDescription") != null) {
sb.append(params.get("SpellDescription"));
sb.append(CardTranslation.translateSingleDescriptionText(params.get("SpellDescription"), sa.getHostCard().getName()));
}
if (sa.getTargets() != null && !sa.getTargets().isEmpty()) {
sb.append(" (Targeting: ").append(sa.getTargets()).append(")");
@@ -98,7 +98,7 @@ public abstract class SpellAbilityEffect {
} else {
final String conditionDesc = sa.getParam("ConditionDescription");
final String afterDesc = sa.getParam("AfterDescription");
final String baseDesc = this.getStackDescription(sa);
final String baseDesc = CardTranslation.translateSingleDescriptionText(this.getStackDescription(sa), sa.getHostCard().getName());
if (conditionDesc != null) {
sb.append(conditionDesc).append(" ");
}
@@ -131,8 +131,8 @@ public abstract class SpellAbilityEffect {
}
String currentName = (sa.getHostCard().getName());
String substitutedDesc = TextUtil.fastReplace(sb.toString(), "CARDNAME", currentName);
substitutedDesc = TextUtil.fastReplace(substitutedDesc, "NICKNAME", currentName.split(",")[0]);
String substitutedDesc = TextUtil.fastReplace(sb.toString(), "CARDNAME", CardTranslation.getTranslatedName(currentName));
substitutedDesc = TextUtil.fastReplace(substitutedDesc, "NICKNAME", Lang.getInstance().getNickName(CardTranslation.getTranslatedName(currentName)));
return substitutedDesc;
}

View File

@@ -2,6 +2,7 @@ package forge.game.ability.effects;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
import forge.util.CardTranslation;
/**
* TODO: Write javadoc for this type.
@@ -13,6 +14,6 @@ public class PermanentNoncreatureEffect extends PermanentEffect {
public String getStackDescription(final SpellAbility sa) {
final Card sourceCard = sa.getHostCard();
//CardView toString return translated name,don't need call CardTranslation.getTranslatedName in this.
return sourceCard.getName();
return CardTranslation.getTranslatedName(sourceCard.getName());
}
}

View File

@@ -2081,7 +2081,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
sbLong.append("\r\n");
}
sb.append(sbLong);
return sb.toString();
return CardTranslation.translateMultipleDescriptionText(sb.toString(), getName());
}
private static String getTextForKwCantBeBlockedByAmount(final String keyword) {
@@ -2119,7 +2119,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
while (result.endsWith("\r\n")) {
result = result.substring(0, result.length() - 2);
}
return TextUtil.fastReplace(result, "CARDNAME", state.getName());
return TextUtil.fastReplace(result, "CARDNAME", CardTranslation.getTranslatedName(state.getName()));
}
if (monstrous) {
@@ -2140,7 +2140,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
for (final ReplacementEffect replacementEffect : state.getReplacementEffects()) {
if (!replacementEffect.isSecondary()) {
String text = replacementEffect.getDescription();
if (text.contains("enters the battlefield")) {
// Get original description since text might be translated
if (replacementEffect.hasParam("Description") &&
replacementEffect.getParam("Description").contains("enters the battlefield")) {
sb.append(text).append("\r\n");
} else {
replacementEffects.append(text).append("\r\n");
@@ -2226,8 +2228,10 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
// add Adventure to AbilityText
if (sa.isAdventure() && state.getView().getState().equals(CardStateName.Original)) {
CardState advState = getState(CardStateName.Adventure);
StringBuilder sbSA = new StringBuilder();
sbSA.append("Adventure — ").append(getState(CardStateName.Adventure).getName());
sbSA.append(Localizer.getInstance().getMessage("lblAdventure"));
sbSA.append("").append(CardTranslation.getTranslatedName(advState.getName()));
sbSA.append(" ").append(sa.getPayCosts().toSimpleString());
sbSA.append(": ");
sbSA.append(sAbility);
@@ -2299,7 +2303,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
start = sb.lastIndexOf(s);
}
String desc = TextUtil.fastReplace(sb.toString(), "CARDNAME", state.getName());
String desc = TextUtil.fastReplace(sb.toString(), "CARDNAME", CardTranslation.getTranslatedName(state.getName()));
if (getEffectSource() != null) {
desc = TextUtil.fastReplace(desc, "EFFECTSOURCE", getEffectSource().getName());
}
@@ -2485,7 +2489,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
}
}
sb.append(sbBefore);
sb.append(CardTranslation.translateMultipleDescriptionText(sbBefore.toString(), state.getName()));
// add Spells there to main StringBuilder
sb.append(strSpell);
@@ -2514,13 +2518,13 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
}
}
sb.append(sbAfter);
sb.append(CardTranslation.translateMultipleDescriptionText(sbAfter.toString(), state.getName()));
return sb;
}
private String formatSpellAbility(final SpellAbility sa) {
final StringBuilder sb = new StringBuilder();
sb.append(sa.toString()).append("\r\n");
sb.append(sa.toString()).append("\r\n\r\n");
return sb.toString();
}

View File

@@ -38,6 +38,7 @@ import forge.game.trigger.TriggerHandler;
import forge.game.trigger.WrappedAbility;
import forge.item.IPaperCard;
import forge.item.PaperCard;
import forge.util.CardTranslation;
import forge.util.TextUtil;
import java.util.Arrays;
@@ -354,6 +355,10 @@ public class CardFactory {
}
private static void readCardFace(Card c, ICardFace face) {
// Build English oracle and translated oracle mapping
if (c.getId() >= 0) {
CardTranslation.buildOracleMapping(face.getName(), face.getOracleText());
}
// Name first so Senty has the Card name
c.setName(face.getName());

View File

@@ -591,14 +591,8 @@ public class CardView extends GameEntityView {
if (translationsText != null) {
tname = translationsText.get("name");
taltname = translationsText.get("altname");
// TODO: Translate for cloned or mutated cards
// For now, don't translate oracles if the card is a cloned or mutated
if (((String) get(TrackableProperty.Cloner)).isEmpty() &&
((String) get(TrackableProperty.MergedCards)).isEmpty()) {
toracle = translationsText.get("oracle");
taltoracle = translationsText.get("altoracle");
}
toracle = translationsText.get("oracle");
taltoracle = translationsText.get("altoracle");
}
if (isSplitCard()) {
@@ -629,18 +623,7 @@ public class CardView extends GameEntityView {
}
final String rulesText = state.getRulesText();
if (!toracle.isEmpty() && !isFaceDown()) {
if (isSplitCard()) {
sb.append("(").append(tname).append(") ");
sb.append(toracle);
sb.append("\r\n\r\n");
sb.append("(").append(taltname).append(") ");
sb.append(taltoracle);
} else {
sb.append(toracle);
}
sb.append("\r\n\r\n");
} else if (!rulesText.isEmpty()) {
if (!rulesText.isEmpty()) {
sb.append(rulesText).append("\r\n\r\n");
}
if (isCommander()) {
@@ -648,15 +631,13 @@ public class CardView extends GameEntityView {
sb.append(getOwner().getCommanderInfo(this)).append("\r\n");
}
if (toracle.isEmpty()) {
if (isSplitCard() && !isFaceDown() && getZone() != ZoneType.Stack) {
sb.append("(").append(getLeftSplitState().getName()).append(") ");
sb.append(getLeftSplitState().getAbilityText());
sb.append("\r\n\r\n").append("(").append(getRightSplitState().getName()).append(") ");
sb.append(getRightSplitState().getAbilityText());
} else {
sb.append(state.getAbilityText());
}
if (isSplitCard() && !isFaceDown() && getZone() != ZoneType.Stack) {
sb.append("(").append(getLeftSplitState().getName()).append(") ");
sb.append(getLeftSplitState().getAbilityText());
sb.append("\r\n\r\n").append("(").append(getRightSplitState().getName()).append(") ");
sb.append(getRightSplitState().getAbilityText());
} else {
sb.append(state.getAbilityText());
}
String nonAbilityText = get(TrackableProperty.NonAbilityText);
@@ -1093,7 +1074,7 @@ public class CardView extends GameEntityView {
return get(TrackableProperty.OracleText);
}
void updateOracleText(Card c) {
set(TrackableProperty.OracleText, c.getOracleText().replace("\\n", "\r\n").trim());
set(TrackableProperty.OracleText, c.getOracleText().replace("\\n", "\r\n\r\n").trim());
}
public String getRulesText() {

View File

@@ -27,7 +27,6 @@ import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.TextUtil;
import forge.util.collect.FCollectionView;
import forge.util.Localizer;
/**
* The Class CostExile.
@@ -89,32 +88,32 @@ public class CostExile extends CostPartWithList {
if (this.payCostFromSource()) {
if (!this.from.equals(ZoneType.Battlefield)) {
return Localizer.getInstance().getMessage("lblExileTargetsFromYourZone", this.getType(), this.from.getTranslatedName());
return String.format("Exile %s from your %s", this.getType(), this.from.name());
}
return Localizer.getInstance().getMessage("lblExileTarget", this.getType());
return String.format("Exile %s", this.getType());
} else if (this.getType().equals("All")) {
return Localizer.getInstance().getMessage("lblExileAllCardsFromYourZone", this.from.getTranslatedName());
return String.format("Exile all cards from your %s", this.from.name());
}
if (this.from.equals(ZoneType.Battlefield)) {
if (!this.payCostFromSource()) {
return Localizer.getInstance().getMessage("lblExileTargetsYourControl", Cost.convertAmountTypeToWords(i, this.getAmount(), desc));
return String.format("Exile %s you control", Cost.convertAmountTypeToWords(i, this.getAmount(), desc));
}
return Localizer.getInstance().getMessage("lblExileTarget", Cost.convertAmountTypeToWords(i, this.getAmount(), desc));
return String.format("Exile %s", Cost.convertAmountTypeToWords(i, this.getAmount(), desc));
}
if (!desc.equals("Card") && !desc.endsWith("card")) {
if (this.sameZone) {
return Localizer.getInstance().getMessage("lblExileNCardFromSameZone", Cost.convertAmountTypeToWords(i, this.getAmount(), desc), this.from.getTranslatedName());
return String.format("Exile card %s from the same %s", Cost.convertAmountTypeToWords(i, this.getAmount(), desc), this.from.name());
}
return Localizer.getInstance().getMessage("lblExileNCardFromYourZone", Cost.convertAmountTypeToWords(i, this.getAmount(), desc), this.from.getTranslatedName());
return String.format("Exile card %s from your %s", Cost.convertAmountTypeToWords(i, this.getAmount(), desc), this.from.name());
}
if (this.sameZone) {
return Localizer.getInstance().getMessage("lblExileNTargetFromSameZone", Cost.convertAmountTypeToWords(i, this.getAmount(), desc), this.from.getTranslatedName());
return String.format("Exile %s from the same %s", Cost.convertAmountTypeToWords(i, this.getAmount(), desc), this.from.name());
}
return Localizer.getInstance().getMessage("lblExileTargetsFromYourZone", Cost.convertAmountTypeToWords(i, this.getAmount(), desc), this.from.getTranslatedName());
return String.format("Exile %s from your %s", Cost.convertAmountTypeToWords(i, this.getAmount(), desc), this.from.name());
}
@Override

View File

@@ -25,6 +25,8 @@ import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.phase.PhaseType;
import forge.game.spellability.SpellAbility;
import forge.util.CardTranslation;
import forge.util.Lang;
import forge.util.TextUtil;
import java.util.List;
@@ -214,15 +216,13 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
public String getDescription() {
if (hasParam("Description") && !this.isSuppressed()) {
String desc = AbilityUtils.applyDescriptionTextChangeEffects(getParam("Description"), this);
if (desc.contains("CARDNAME")) {
desc = TextUtil.fastReplace(desc, "CARDNAME", getHostCard().toString());
}
String currentName = getHostCard().getName();
desc = CardTranslation.translateSingleDescriptionText(desc, currentName);
desc = TextUtil.fastReplace(desc, "CARDNAME", CardTranslation.getTranslatedName(currentName));
desc = TextUtil.fastReplace(desc, "NICKNAME", Lang.getInstance().getNickName(CardTranslation.getTranslatedName(currentName)));
if (desc.contains("EFFECTSOURCE")) {
desc = TextUtil.fastReplace(desc, "EFFECTSOURCE", getHostCard().getEffectSource().toString());
}
if (desc.contains("NICKNAME")) {
desc = TextUtil.fastReplace(desc, "NICKNAME", getHostCard().toString().split(",")[0]);
}
return desc;
} else {
return "";

View File

@@ -54,7 +54,9 @@ import forge.game.trigger.TriggerType;
import forge.game.trigger.WrappedAbility;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.CardTranslation;
import forge.util.Expressions;
import forge.util.Lang;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils;
@@ -814,8 +816,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
}
String desc = node.getDescription();
if (node.getHostCard() != null) {
desc = TextUtil.fastReplace(desc, "CARDNAME", node.getHostCard().getName());
desc = TextUtil.fastReplace(desc,"NICKNAME",node.getHostCard().getName().split(",")[0]);
String currentName = node.getHostCard().getName();
desc = CardTranslation.translateMultipleDescriptionText(desc, currentName);
desc = TextUtil.fastReplace(desc, "CARDNAME", CardTranslation.getTranslatedName(currentName));
desc = TextUtil.fastReplace(desc, "NICKNAME", Lang.getInstance().getNickName(CardTranslation.getTranslatedName(currentName)));
if (node.getOriginalHost() != null) {
desc = TextUtil.fastReplace(desc, "ORIGINALHOST", node.getOriginalHost().getName());
}

View File

@@ -39,7 +39,9 @@ import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.util.CardTranslation;
import forge.util.Expressions;
import forge.util.Lang;
import forge.util.TextUtil;
import java.util.EnumSet;
@@ -214,9 +216,10 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
@Override
public final String toString() {
if (hasParam("Description") && !this.isSuppressed()) {
String desc = getParam("Description");
desc = TextUtil.fastReplace(desc, "CARDNAME", this.hostCard.getName());
desc = TextUtil.fastReplace(desc, "NICKNAME", this.hostCard.getName().split(",")[0]);
String currentName = this.hostCard.getName();
String desc = CardTranslation.translateSingleDescriptionText(getParam("Description"), currentName);
desc = TextUtil.fastReplace(desc, "CARDNAME", CardTranslation.getTranslatedName(currentName));
desc = TextUtil.fastReplace(desc, "NICKNAME", Lang.getInstance().getNickName(CardTranslation.getTranslatedName(currentName)));
return desc;
} else {

View File

@@ -39,6 +39,8 @@ import java.util.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import forge.util.CardTranslation;
import forge.util.Lang;
import forge.util.TextUtil;
/**
@@ -124,9 +126,13 @@ public abstract class Trigger extends TriggerReplacementBase {
if (hasParam("TriggerDescription") && !this.isSuppressed()) {
StringBuilder sb = new StringBuilder();
String currentName = (getHostCard().getName());
String desc1 = TextUtil.fastReplace(getParam("TriggerDescription"),"CARDNAME", currentName);
String desc = TextUtil.fastReplace(desc1,"NICKNAME", currentName.split(",")[0]);
String currentName = getHostCard().getName();
String desc = getParam("TriggerDescription");
if (!desc.contains("ABILITY")) {
desc = CardTranslation.translateSingleDescriptionText(getParam("TriggerDescription"), currentName);
desc = TextUtil.fastReplace(desc,"CARDNAME", CardTranslation.getTranslatedName(currentName));
desc = TextUtil.fastReplace(desc,"NICKNAME", Lang.getInstance().getNickName(CardTranslation.getTranslatedName(currentName)));
}
if (getHostCard().getEffectSource() != null) {
if(active)
desc = TextUtil.fastReplace(desc, "EFFECTSOURCE", getHostCard().getEffectSource().toString());
@@ -198,6 +204,11 @@ public abstract class Trigger extends TriggerReplacementBase {
saDesc = "<take no action>"; // printed in case nothing is chosen for the ability (e.g. Charm with Up to X)
}
result = TextUtil.fastReplace(result, "ABILITY", saDesc);
String currentName = sa.getHostCard().getName();
result = CardTranslation.translateMultipleDescriptionText(result, currentName);
result = TextUtil.fastReplace(result,"CARDNAME", CardTranslation.getTranslatedName(currentName));
result = TextUtil.fastReplace(result,"NICKNAME", Lang.getInstance().getNickName(CardTranslation.getTranslatedName(currentName)));
}
return result;