summaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorGravatar modmuss502020-03-05 22:17:08 +0000
committerGravatar GitHub2020-03-05 22:17:08 +0000
commit863d40a1c1f6591ef1ee8594b12ae4b0942fe810 (patch)
tree614c0e3bc842e1ab50413dcc18b450c96224db10 /src/main
parentFix drop mappings not checking localVars (diff)
downloadenigma-863d40a1c1f6591ef1ee8594b12ae4b0942fe810.tar.gz
enigma-863d40a1c1f6591ef1ee8594b12ae4b0942fe810.tar.xz
enigma-863d40a1c1f6591ef1ee8594b12ae4b0942fe810.zip
Made Enigma gui translatable (#193)
* made enigma gui translatable * key renamings * missed strings * string.format() & another missed string * cached content (thanks @liach) * added a dialog when changing language * better sentence * more %s * liach's requests * empty map * the last (?) missed strings * IT WORKS * French translation * Update fr_fr.json
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/cuchaz/enigma/Constants.java2
-rw-r--r--src/main/java/cuchaz/enigma/EnigmaProject.java12
-rw-r--r--src/main/java/cuchaz/enigma/Main.java1
-rw-r--r--src/main/java/cuchaz/enigma/analysis/index/JarIndex.java12
-rw-r--r--src/main/java/cuchaz/enigma/config/Config.java5
-rw-r--r--src/main/java/cuchaz/enigma/gui/Gui.java49
-rw-r--r--src/main/java/cuchaz/enigma/gui/GuiController.java5
-rw-r--r--src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java5
-rw-r--r--src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java11
-rw-r--r--src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java9
-rw-r--r--src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java3
-rw-r--r--src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java3
-rw-r--r--src/main/java/cuchaz/enigma/gui/elements/MenuBar.java81
-rw-r--r--src/main/java/cuchaz/enigma/gui/elements/PopupMenuBar.java21
-rw-r--r--src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java3
-rw-r--r--src/main/java/cuchaz/enigma/gui/panels/PanelIdentifier.java5
-rw-r--r--src/main/java/cuchaz/enigma/gui/panels/PanelObf.java3
-rw-r--r--src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java11
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsReader.java7
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java5
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/serde/SrgMappingsWriter.java11
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsReader.java3
-rw-r--r--src/main/java/cuchaz/enigma/translation/mapping/serde/TinyV2Reader.java3
-rw-r--r--src/main/java/cuchaz/enigma/utils/I18n.java102
-rw-r--r--src/main/resources/lang/en_us.json115
-rw-r--r--src/main/resources/lang/fr_fr.json115
26 files changed, 494 insertions, 108 deletions
diff --git a/src/main/java/cuchaz/enigma/Constants.java b/src/main/java/cuchaz/enigma/Constants.java
index afffb5d3..577315ff 100644
--- a/src/main/java/cuchaz/enigma/Constants.java
+++ b/src/main/java/cuchaz/enigma/Constants.java
@@ -14,7 +14,7 @@ package cuchaz.enigma;
14public class Constants { 14public class Constants {
15 public static final String NAME = "Enigma"; 15 public static final String NAME = "Enigma";
16 public static final String VERSION = "@VERSION@/Fabric"; 16 public static final String VERSION = "@VERSION@/Fabric";
17 public static final String URL = "https://fabric.asie.pl"; 17 public static final String URL = "https://fabricmc.net";
18 public static final int MiB = 1024 * 1024; // 1 mebibyte 18 public static final int MiB = 1024 * 1024; // 1 mebibyte
19 public static final int KiB = 1024; // 1 kebibyte 19 public static final int KiB = 1024; // 1 kebibyte
20} 20}
diff --git a/src/main/java/cuchaz/enigma/EnigmaProject.java b/src/main/java/cuchaz/enigma/EnigmaProject.java
index 2a7ca988..fddacccf 100644
--- a/src/main/java/cuchaz/enigma/EnigmaProject.java
+++ b/src/main/java/cuchaz/enigma/EnigmaProject.java
@@ -19,6 +19,8 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
19import cuchaz.enigma.translation.representation.entry.Entry; 19import cuchaz.enigma.translation.representation.entry.Entry;
20import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; 20import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
21import cuchaz.enigma.translation.representation.entry.MethodEntry; 21import cuchaz.enigma.translation.representation.entry.MethodEntry;
22import cuchaz.enigma.utils.I18n;
23
22import org.objectweb.asm.ClassWriter; 24import org.objectweb.asm.ClassWriter;
23import org.objectweb.asm.Opcodes; 25import org.objectweb.asm.Opcodes;
24import org.objectweb.asm.tree.ClassNode; 26import org.objectweb.asm.tree.ClassNode;
@@ -32,12 +34,10 @@ import java.nio.file.Path;
32import java.util.Collection; 34import java.util.Collection;
33import java.util.Map; 35import java.util.Map;
34import java.util.Objects; 36import java.util.Objects;
35import java.util.Optional;
36import java.util.concurrent.atomic.AtomicInteger; 37import java.util.concurrent.atomic.AtomicInteger;
37import java.util.jar.JarEntry; 38import java.util.jar.JarEntry;
38import java.util.jar.JarOutputStream; 39import java.util.jar.JarOutputStream;
39import java.util.stream.Collectors; 40import java.util.stream.Collectors;
40import java.util.stream.Stream;
41 41
42public class EnigmaProject { 42public class EnigmaProject {
43 private final Enigma enigma; 43 private final Enigma enigma;
@@ -148,7 +148,7 @@ public class EnigmaProject {
148 Translator deobfuscator = nameProposalServices.length == 0 ? mapper.getDeobfuscator() : new ProposingTranslator(mapper, nameProposalServices); 148 Translator deobfuscator = nameProposalServices.length == 0 ? mapper.getDeobfuscator() : new ProposingTranslator(mapper, nameProposalServices);
149 149
150 AtomicInteger count = new AtomicInteger(); 150 AtomicInteger count = new AtomicInteger();
151 progress.init(classEntries.size(), "Deobfuscating classes..."); 151 progress.init(classEntries.size(), I18n.translate("progress.classes.deobfuscating"));
152 152
153 Map<String, ClassNode> compiled = classEntries.parallelStream() 153 Map<String, ClassNode> compiled = classEntries.parallelStream()
154 .map(entry -> { 154 .map(entry -> {
@@ -180,7 +180,7 @@ public class EnigmaProject {
180 } 180 }
181 181
182 public void write(Path path, ProgressListener progress) throws IOException { 182 public void write(Path path, ProgressListener progress) throws IOException {
183 progress.init(this.compiled.size(), "Writing jar..."); 183 progress.init(this.compiled.size(), I18n.translate("progress.jar.writing"));
184 184
185 try (JarOutputStream out = new JarOutputStream(Files.newOutputStream(path))) { 185 try (JarOutputStream out = new JarOutputStream(Files.newOutputStream(path))) {
186 AtomicInteger count = new AtomicInteger(); 186 AtomicInteger count = new AtomicInteger();
@@ -205,7 +205,7 @@ public class EnigmaProject {
205 .filter(classNode -> classNode.name.indexOf('$') == -1) 205 .filter(classNode -> classNode.name.indexOf('$') == -1)
206 .collect(Collectors.toList()); 206 .collect(Collectors.toList());
207 207
208 progress.init(classes.size(), "Decompiling classes..."); 208 progress.init(classes.size(), I18n.translate("progress.classes.decompiling"));
209 209
210 //create a common instance outside the loop as mappings shouldn't be changing while this is happening 210 //create a common instance outside the loop as mappings shouldn't be changing while this is happening
211 CompiledSourceTypeLoader typeLoader = new CompiledSourceTypeLoader(this.compiled::get); 211 CompiledSourceTypeLoader typeLoader = new CompiledSourceTypeLoader(this.compiled::get);
@@ -256,7 +256,7 @@ public class EnigmaProject {
256 } 256 }
257 257
258 public void write(Path path, ProgressListener progress) throws IOException { 258 public void write(Path path, ProgressListener progress) throws IOException {
259 progress.init(decompiled.size(), "Writing sources..."); 259 progress.init(decompiled.size(), I18n.translate("progress.sources.writing"));
260 260
261 int count = 0; 261 int count = 0;
262 for (ClassSource source : decompiled) { 262 for (ClassSource source : decompiled) {
diff --git a/src/main/java/cuchaz/enigma/Main.java b/src/main/java/cuchaz/enigma/Main.java
index dbbcee42..ceb5554b 100644
--- a/src/main/java/cuchaz/enigma/Main.java
+++ b/src/main/java/cuchaz/enigma/Main.java
@@ -14,6 +14,7 @@ package cuchaz.enigma;
14import cuchaz.enigma.gui.Gui; 14import cuchaz.enigma.gui.Gui;
15import cuchaz.enigma.gui.GuiController; 15import cuchaz.enigma.gui.GuiController;
16import cuchaz.enigma.translation.mapping.serde.MappingFormat; 16import cuchaz.enigma.translation.mapping.serde.MappingFormat;
17
17import joptsimple.*; 18import joptsimple.*;
18 19
19import java.io.BufferedReader; 20import java.io.BufferedReader;
diff --git a/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java b/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
index 8e92dd86..c96e7747 100644
--- a/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
+++ b/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
@@ -20,6 +20,8 @@ import cuchaz.enigma.translation.mapping.EntryResolver;
20import cuchaz.enigma.translation.mapping.IndexEntryResolver; 20import cuchaz.enigma.translation.mapping.IndexEntryResolver;
21import cuchaz.enigma.translation.representation.Lambda; 21import cuchaz.enigma.translation.representation.Lambda;
22import cuchaz.enigma.translation.representation.entry.*; 22import cuchaz.enigma.translation.representation.entry.*;
23import cuchaz.enigma.utils.I18n;
24
23import org.objectweb.asm.ClassReader; 25import org.objectweb.asm.ClassReader;
24import org.objectweb.asm.Opcodes; 26import org.objectweb.asm.Opcodes;
25 27
@@ -58,18 +60,18 @@ public class JarIndex implements JarIndexer {
58 } 60 }
59 61
60 public void indexJar(ClassCache classCache, ProgressListener progress) { 62 public void indexJar(ClassCache classCache, ProgressListener progress) {
61 progress.init(4, "Indexing jar"); 63 progress.init(4, I18n.translate("progress.jar.indexing"));
62 64
63 progress.step(1, "Entries..."); 65 progress.step(1, I18n.translate("progress.jar.indexing.entries"));
64 classCache.visit(() -> new IndexClassVisitor(this, Opcodes.ASM5), ClassReader.SKIP_CODE); 66 classCache.visit(() -> new IndexClassVisitor(this, Opcodes.ASM5), ClassReader.SKIP_CODE);
65 67
66 progress.step(2, "Entry references..."); 68 progress.step(2, I18n.translate("progress.jar.indexing.references"));
67 classCache.visit(() -> new IndexReferenceVisitor(this, entryIndex, inheritanceIndex, Opcodes.ASM5), 0); 69 classCache.visit(() -> new IndexReferenceVisitor(this, entryIndex, inheritanceIndex, Opcodes.ASM5), 0);
68 70
69 progress.step(3, "Bridge methods..."); 71 progress.step(3, I18n.translate("progress.jar.indexing.methods"));
70 bridgeMethodIndex.findBridgeMethods(); 72 bridgeMethodIndex.findBridgeMethods();
71 73
72 progress.step(4, "Processing..."); 74 progress.step(4, I18n.translate("progress.jar.indexing.process"));
73 processIndex(this); 75 processIndex(this);
74 } 76 }
75 77
diff --git a/src/main/java/cuchaz/enigma/config/Config.java b/src/main/java/cuchaz/enigma/config/Config.java
index e2afb018..a00fe2df 100644
--- a/src/main/java/cuchaz/enigma/config/Config.java
+++ b/src/main/java/cuchaz/enigma/config/Config.java
@@ -4,6 +4,8 @@ import com.bulenkov.darcula.DarculaLaf;
4import com.google.common.io.Files; 4import com.google.common.io.Files;
5import com.google.gson.*; 5import com.google.gson.*;
6 6
7import cuchaz.enigma.utils.I18n;
8
7import javax.swing.*; 9import javax.swing.*;
8import javax.swing.plaf.metal.MetalLookAndFeel; 10import javax.swing.plaf.metal.MetalLookAndFeel;
9import java.awt.*; 11import java.awt.*;
@@ -165,6 +167,8 @@ public class Config {
165 public Integer lineNumbersBackground; 167 public Integer lineNumbersBackground;
166 public Integer lineNumbersSelected; 168 public Integer lineNumbersSelected;
167 public Integer lineNumbersForeground; 169 public Integer lineNumbersForeground;
170
171 public String language = I18n.DEFAULT_LANGUAGE;
168 172
169 public LookAndFeel lookAndFeel = LookAndFeel.DEFAULT; 173 public LookAndFeel lookAndFeel = LookAndFeel.DEFAULT;
170 174
@@ -213,6 +217,7 @@ public class Config {
213 public void reset() throws IOException { 217 public void reset() throws IOException {
214 this.lookAndFeel = LookAndFeel.DEFAULT; 218 this.lookAndFeel = LookAndFeel.DEFAULT;
215 this.lookAndFeel.apply(this); 219 this.lookAndFeel.apply(this);
220 this.language = I18n.DEFAULT_LANGUAGE;
216 this.saveConfig(); 221 this.saveConfig();
217 } 222 }
218 223
diff --git a/src/main/java/cuchaz/enigma/gui/Gui.java b/src/main/java/cuchaz/enigma/gui/Gui.java
index 1ea3e44f..5eeb07de 100644
--- a/src/main/java/cuchaz/enigma/gui/Gui.java
+++ b/src/main/java/cuchaz/enigma/gui/Gui.java
@@ -36,6 +36,7 @@ import cuchaz.enigma.gui.util.History;
36import cuchaz.enigma.throwables.IllegalNameException; 36import cuchaz.enigma.throwables.IllegalNameException;
37import cuchaz.enigma.translation.mapping.*; 37import cuchaz.enigma.translation.mapping.*;
38import cuchaz.enigma.translation.representation.entry.*; 38import cuchaz.enigma.translation.representation.entry.*;
39import cuchaz.enigma.utils.I18n;
39import cuchaz.enigma.utils.Utils; 40import cuchaz.enigma.utils.Utils;
40import de.sciss.syntaxpane.DefaultSyntaxKit; 41import de.sciss.syntaxpane.DefaultSyntaxKit;
41 42
@@ -120,12 +121,12 @@ public class Gui {
120 this.controller = new GuiController(this, profile); 121 this.controller = new GuiController(this, profile);
121 122
122 // init file choosers 123 // init file choosers
123 this.jarFileChooser = new FileDialog(getFrame(), "Open Jar", FileDialog.LOAD); 124 this.jarFileChooser = new FileDialog(getFrame(), I18n.translate("menu.file.jar.open"), FileDialog.LOAD);
124 125
125 this.tinyMappingsFileChooser = new FileDialog(getFrame(), "Open tiny Mappings", FileDialog.LOAD); 126 this.tinyMappingsFileChooser = new FileDialog(getFrame(), "Open tiny Mappings", FileDialog.LOAD);
126 this.enigmaMappingsFileChooser = new FileChooserAny(); 127 this.enigmaMappingsFileChooser = new FileChooserAny();
127 this.exportSourceFileChooser = new FileChooserFolder(); 128 this.exportSourceFileChooser = new FileChooserFolder();
128 this.exportJarFileChooser = new FileDialog(getFrame(), "Export jar", FileDialog.SAVE); 129 this.exportJarFileChooser = new FileDialog(getFrame(), I18n.translate("menu.file.export.jar"), FileDialog.SAVE);
129 130
130 this.obfPanel = new PanelObf(this); 131 this.obfPanel = new PanelObf(this);
131 this.deobfPanel = new PanelDeobf(this); 132 this.deobfPanel = new PanelDeobf(this);
@@ -275,9 +276,9 @@ public class Gui {
275 centerPanel.add(sourceScroller, BorderLayout.CENTER); 276 centerPanel.add(sourceScroller, BorderLayout.CENTER);
276 tabs = new JTabbedPane(); 277 tabs = new JTabbedPane();
277 tabs.setPreferredSize(new Dimension(250, 0)); 278 tabs.setPreferredSize(new Dimension(250, 0));
278 tabs.addTab("Inheritance", inheritancePanel); 279 tabs.addTab(I18n.translate("info_panel.tree.inheritance"), inheritancePanel);
279 tabs.addTab("Implementations", implementationsPanel); 280 tabs.addTab(I18n.translate("info_panel.tree.implementations"), implementationsPanel);
280 tabs.addTab("Call Graph", callPanel); 281 tabs.addTab(I18n.translate("info_panel.tree.calls"), callPanel);
281 JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, tabs); 282 JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, tabs);
282 splitRight.setResizeWeight(1); // let the left side take all the slack 283 splitRight.setResizeWeight(1); // let the left side take all the slack
283 splitRight.resetToPreferredSizes(); 284 splitRight.resetToPreferredSizes();
@@ -458,33 +459,33 @@ public class Gui {
458 } 459 }
459 460
460 private void showLocalVariableEntry(LocalVariableEntry entry) { 461 private void showLocalVariableEntry(LocalVariableEntry entry) {
461 addNameValue(infoPanel, "Variable", entry.getName()); 462 addNameValue(infoPanel, I18n.translate("info_panel.identifier.variable"), entry.getName());
462 addNameValue(infoPanel, "Class", entry.getContainingClass().getFullName()); 463 addNameValue(infoPanel, I18n.translate("info_panel.identifier.class"), entry.getContainingClass().getFullName());
463 addNameValue(infoPanel, "Method", entry.getParent().getName()); 464 addNameValue(infoPanel, I18n.translate("info_panel.identifier.method"), entry.getParent().getName());
464 addNameValue(infoPanel, "Index", Integer.toString(entry.getIndex())); 465 addNameValue(infoPanel, I18n.translate("info_panel.identifier.index"), Integer.toString(entry.getIndex()));
465 } 466 }
466 467
467 private void showClassEntry(ClassEntry entry) { 468 private void showClassEntry(ClassEntry entry) {
468 addNameValue(infoPanel, "Class", entry.getFullName()); 469 addNameValue(infoPanel, I18n.translate("info_panel.identifier.class"), entry.getFullName());
469 addModifierComboBox(infoPanel, "Modifier", entry); 470 addModifierComboBox(infoPanel, I18n.translate("info_panel.identifier.modifier"), entry);
470 } 471 }
471 472
472 private void showFieldEntry(FieldEntry entry) { 473 private void showFieldEntry(FieldEntry entry) {
473 addNameValue(infoPanel, "Field", entry.getName()); 474 addNameValue(infoPanel, I18n.translate("info_panel.identifier.field"), entry.getName());
474 addNameValue(infoPanel, "Class", entry.getParent().getFullName()); 475 addNameValue(infoPanel, I18n.translate("info_panel.identifier.class"), entry.getParent().getFullName());
475 addNameValue(infoPanel, "TypeDescriptor", entry.getDesc().toString()); 476 addNameValue(infoPanel, I18n.translate("info_panel.identifier.type_descriptor"), entry.getDesc().toString());
476 addModifierComboBox(infoPanel, "Modifier", entry); 477 addModifierComboBox(infoPanel, I18n.translate("info_panel.identifier.modifier"), entry);
477 } 478 }
478 479
479 private void showMethodEntry(MethodEntry entry) { 480 private void showMethodEntry(MethodEntry entry) {
480 if (entry.isConstructor()) { 481 if (entry.isConstructor()) {
481 addNameValue(infoPanel, "Constructor", entry.getParent().getFullName()); 482 addNameValue(infoPanel, I18n.translate("info_panel.identifier.constructor"), entry.getParent().getFullName());
482 } else { 483 } else {
483 addNameValue(infoPanel, "Method", entry.getName()); 484 addNameValue(infoPanel, I18n.translate("info_panel.identifier.method"), entry.getName());
484 addNameValue(infoPanel, "Class", entry.getParent().getFullName()); 485 addNameValue(infoPanel, I18n.translate("info_panel.identifier.class"), entry.getParent().getFullName());
485 } 486 }
486 addNameValue(infoPanel, "MethodDescriptor", entry.getDesc().toString()); 487 addNameValue(infoPanel, I18n.translate("info_panel.identifier.method_descriptor"), entry.getDesc().toString());
487 addModifierComboBox(infoPanel, "Modifier", entry); 488 addModifierComboBox(infoPanel, I18n.translate("info_panel.identifier.modifier"), entry);
488 } 489 }
489 490
490 private void addNameValue(JPanel container, String name, String value) { 491 private void addNameValue(JPanel container, String name, String value) {
@@ -573,9 +574,9 @@ public class Gui {
573 this.popupMenu.toggleMappingMenu.setEnabled(isRenamable); 574 this.popupMenu.toggleMappingMenu.setEnabled(isRenamable);
574 575
575 if (isToken && !Objects.equals(referenceEntry, mapper.deobfuscate(referenceEntry))) { 576 if (isToken && !Objects.equals(referenceEntry, mapper.deobfuscate(referenceEntry))) {
576 this.popupMenu.toggleMappingMenu.setText("Reset to obfuscated"); 577 this.popupMenu.toggleMappingMenu.setText(I18n.translate("popup_menu.reset_obfuscated"));
577 } else { 578 } else {
578 this.popupMenu.toggleMappingMenu.setText("Mark as deobfuscated"); 579 this.popupMenu.toggleMappingMenu.setText(I18n.translate("popup_menu.mark_deobfuscated"));
579 } 580 }
580 } 581 }
581 582
@@ -794,7 +795,7 @@ public class Gui {
794 } 795 }
795 796
796 public void showDiscardDiag(Function<Integer, Void> callback, String... options) { 797 public void showDiscardDiag(Function<Integer, Void> callback, String... options) {
797 int response = JOptionPane.showOptionDialog(this.frame, "Your mappings have not been saved yet. Do you want to save?", "Save your changes?", JOptionPane.YES_NO_CANCEL_OPTION, 798 int response = JOptionPane.showOptionDialog(this.frame, I18n.translate("prompt.close.summary"), I18n.translate("prompt.close.title"), JOptionPane.YES_NO_CANCEL_OPTION,
798 JOptionPane.QUESTION_MESSAGE, null, options, options[2]); 799 JOptionPane.QUESTION_MESSAGE, null, options, options[2]);
799 callback.apply(response); 800 callback.apply(response);
800 } 801 }
@@ -820,7 +821,7 @@ public class Gui {
820 } 821 }
821 822
822 return null; 823 return null;
823 }, "Save and exit", "Discard changes", "Cancel"); 824 }, I18n.translate("prompt.close.save"), I18n.translate("prompt.close.discard"), I18n.translate("prompt.close.cancel"));
824 } 825 }
825 } 826 }
826 827
diff --git a/src/main/java/cuchaz/enigma/gui/GuiController.java b/src/main/java/cuchaz/enigma/gui/GuiController.java
index 0b2fe27d..dc5010cb 100644
--- a/src/main/java/cuchaz/enigma/gui/GuiController.java
+++ b/src/main/java/cuchaz/enigma/gui/GuiController.java
@@ -32,6 +32,7 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
32import cuchaz.enigma.translation.representation.entry.Entry; 32import cuchaz.enigma.translation.representation.entry.Entry;
33import cuchaz.enigma.translation.representation.entry.FieldEntry; 33import cuchaz.enigma.translation.representation.entry.FieldEntry;
34import cuchaz.enigma.translation.representation.entry.MethodEntry; 34import cuchaz.enigma.translation.representation.entry.MethodEntry;
35import cuchaz.enigma.utils.I18n;
35import cuchaz.enigma.utils.ReadableToken; 36import cuchaz.enigma.utils.ReadableToken;
36import cuchaz.enigma.utils.Utils; 37import cuchaz.enigma.utils.Utils;
37import org.objectweb.asm.Opcodes; 38import org.objectweb.asm.Opcodes;
@@ -391,7 +392,7 @@ public class GuiController {
391 boolean requiresDecompile = forceDecomp || currentSource == null || !currentSource.getEntry().equals(targetClass); 392 boolean requiresDecompile = forceDecomp || currentSource == null || !currentSource.getEntry().equals(targetClass);
392 if (requiresDecompile) { 393 if (requiresDecompile) {
393 currentSource = null; // Or the GUI may try to find a nonexistent token 394 currentSource = null; // Or the GUI may try to find a nonexistent token
394 gui.setEditorText("(decompiling...)"); 395 gui.setEditorText(I18n.translate("info_panel.editor.class.decompiling"));
395 } 396 }
396 397
397 DECOMPILER_SERVICE.submit(() -> { 398 DECOMPILER_SERVICE.submit(() -> {
@@ -413,7 +414,7 @@ public class GuiController {
413 try { 414 try {
414 CompilationUnit sourceTree = (CompilationUnit) sourceProvider.getSources(targetClass.getFullName()).clone(); 415 CompilationUnit sourceTree = (CompilationUnit) sourceProvider.getSources(targetClass.getFullName()).clone();
415 if (sourceTree == null) { 416 if (sourceTree == null) {
416 gui.setEditorText("Unable to find class: " + targetClass); 417 gui.setEditorText(I18n.translate("info_panel.editor.class.not_found") + " " + targetClass);
417 return DecompiledClassSource.text(targetClass, "Unable to find class"); 418 return DecompiledClassSource.text(targetClass, "Unable to find class");
418 } 419 }
419 420
diff --git a/src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java b/src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java
index 7b3234d8..82fd6a5c 100644
--- a/src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java
+++ b/src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java
@@ -12,6 +12,7 @@
12package cuchaz.enigma.gui.dialog; 12package cuchaz.enigma.gui.dialog;
13 13
14import cuchaz.enigma.Constants; 14import cuchaz.enigma.Constants;
15import cuchaz.enigma.utils.I18n;
15import cuchaz.enigma.utils.Utils; 16import cuchaz.enigma.utils.Utils;
16 17
17import javax.swing.*; 18import javax.swing.*;
@@ -22,7 +23,7 @@ public class AboutDialog {
22 23
23 public static void show(JFrame parent) { 24 public static void show(JFrame parent) {
24 // init frame 25 // init frame
25 final JFrame frame = new JFrame(Constants.NAME + " - About"); 26 final JFrame frame = new JFrame(String.format(I18n.translate("menu.help.about.title"), Constants.NAME));
26 final Container pane = frame.getContentPane(); 27 final Container pane = frame.getContentPane();
27 pane.setLayout(new FlowLayout()); 28 pane.setLayout(new FlowLayout());
28 29
@@ -52,7 +53,7 @@ public class AboutDialog {
52 pane.add(linkPanel); 53 pane.add(linkPanel);
53 54
54 // show ok button 55 // show ok button
55 JButton okButton = new JButton("Ok"); 56 JButton okButton = new JButton(I18n.translate("menu.help.about.ok"));
56 pane.add(okButton); 57 pane.add(okButton);
57 okButton.addActionListener(arg0 -> frame.dispose()); 58 okButton.addActionListener(arg0 -> frame.dispose());
58 59
diff --git a/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java b/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java
index 04dd5d7b..7e66ecde 100644
--- a/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java
+++ b/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java
@@ -12,6 +12,7 @@
12package cuchaz.enigma.gui.dialog; 12package cuchaz.enigma.gui.dialog;
13 13
14import cuchaz.enigma.Constants; 14import cuchaz.enigma.Constants;
15import cuchaz.enigma.utils.I18n;
15import cuchaz.enigma.utils.Utils; 16import cuchaz.enigma.utils.Utils;
16 17
17import javax.swing.*; 18import javax.swing.*;
@@ -28,11 +29,11 @@ public class CrashDialog {
28 29
29 private CrashDialog(JFrame parent) { 30 private CrashDialog(JFrame parent) {
30 // init frame 31 // init frame
31 frame = new JFrame(Constants.NAME + " - Crash Report"); 32 frame = new JFrame(String.format(I18n.translate("crash.title"), Constants.NAME));
32 final Container pane = frame.getContentPane(); 33 final Container pane = frame.getContentPane();
33 pane.setLayout(new BorderLayout()); 34 pane.setLayout(new BorderLayout());
34 35
35 JLabel label = new JLabel(Constants.NAME + " has crashed! =("); 36 JLabel label = new JLabel(String.format(I18n.translate("crash.summary"), Constants.NAME));
36 label.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 37 label.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
37 pane.add(label, BorderLayout.NORTH); 38 pane.add(label, BorderLayout.NORTH);
38 39
@@ -46,14 +47,14 @@ public class CrashDialog {
46 FlowLayout buttonsLayout = new FlowLayout(); 47 FlowLayout buttonsLayout = new FlowLayout();
47 buttonsLayout.setAlignment(FlowLayout.RIGHT); 48 buttonsLayout.setAlignment(FlowLayout.RIGHT);
48 buttonsPanel.setLayout(buttonsLayout); 49 buttonsPanel.setLayout(buttonsLayout);
49 buttonsPanel.add(Utils.unboldLabel(new JLabel("If you choose exit, you will lose any unsaved work."))); 50 buttonsPanel.add(Utils.unboldLabel(new JLabel(I18n.translate("crash.exit.warning"))));
50 JButton ignoreButton = new JButton("Ignore"); 51 JButton ignoreButton = new JButton(I18n.translate("crash.ignore"));
51 ignoreButton.addActionListener(event -> { 52 ignoreButton.addActionListener(event -> {
52 // close (hide) the dialog 53 // close (hide) the dialog
53 frame.setVisible(false); 54 frame.setVisible(false);
54 }); 55 });
55 buttonsPanel.add(ignoreButton); 56 buttonsPanel.add(ignoreButton);
56 JButton exitButton = new JButton("Exit"); 57 JButton exitButton = new JButton(I18n.translate("crash.exit"));
57 exitButton.addActionListener(event -> { 58 exitButton.addActionListener(event -> {
58 // exit enigma 59 // exit enigma
59 System.exit(1); 60 System.exit(1);
diff --git a/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java b/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java
index 84e4d8fc..57811eef 100644
--- a/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java
+++ b/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java
@@ -11,6 +11,7 @@
11 11
12package cuchaz.enigma.gui.dialog; 12package cuchaz.enigma.gui.dialog;
13 13
14import cuchaz.enigma.utils.I18n;
14import cuchaz.enigma.utils.Utils; 15import cuchaz.enigma.utils.Utils;
15 16
16import javax.swing.*; 17import javax.swing.*;
@@ -26,7 +27,7 @@ public class JavadocDialog {
26 27
27 private JavadocDialog(JFrame parent, JTextArea text, Callback callback) { 28 private JavadocDialog(JFrame parent, JTextArea text, Callback callback) {
28 // init frame 29 // init frame
29 frame = new JFrame("Edit Javadocs"); 30 frame = new JFrame(I18n.translate("javadocs.edit"));
30 final Container pane = frame.getContentPane(); 31 final Container pane = frame.getContentPane();
31 pane.setLayout(new BorderLayout()); 32 pane.setLayout(new BorderLayout());
32 33
@@ -55,14 +56,14 @@ public class JavadocDialog {
55 FlowLayout buttonsLayout = new FlowLayout(); 56 FlowLayout buttonsLayout = new FlowLayout();
56 buttonsLayout.setAlignment(FlowLayout.RIGHT); 57 buttonsLayout.setAlignment(FlowLayout.RIGHT);
57 buttonsPanel.setLayout(buttonsLayout); 58 buttonsPanel.setLayout(buttonsLayout);
58 buttonsPanel.add(Utils.unboldLabel(new JLabel("Edit javadocs here."))); 59 buttonsPanel.add(Utils.unboldLabel(new JLabel(I18n.translate("javadocs.instruction"))));
59 JButton cancelButton = new JButton("Cancel"); 60 JButton cancelButton = new JButton(I18n.translate("javadocs.cancel"));
60 cancelButton.addActionListener(event -> { 61 cancelButton.addActionListener(event -> {
61 // close (hide) the dialog 62 // close (hide) the dialog
62 callback.closeUi(frame, false); 63 callback.closeUi(frame, false);
63 }); 64 });
64 buttonsPanel.add(cancelButton); 65 buttonsPanel.add(cancelButton);
65 JButton saveButton = new JButton("Save"); 66 JButton saveButton = new JButton(I18n.translate("javadocs.save"));
66 saveButton.addActionListener(event -> { 67 saveButton.addActionListener(event -> {
67 // exit enigma 68 // exit enigma
68 callback.closeUi(frame, true); 69 callback.closeUi(frame, true);
diff --git a/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java b/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java
index ae30667c..6d9a4198 100644
--- a/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java
+++ b/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java
@@ -13,6 +13,7 @@ package cuchaz.enigma.gui.dialog;
13 13
14import cuchaz.enigma.Constants; 14import cuchaz.enigma.Constants;
15import cuchaz.enigma.ProgressListener; 15import cuchaz.enigma.ProgressListener;
16import cuchaz.enigma.utils.I18n;
16import cuchaz.enigma.utils.Utils; 17import cuchaz.enigma.utils.Utils;
17 18
18import javax.swing.*; 19import javax.swing.*;
@@ -29,7 +30,7 @@ public class ProgressDialog implements ProgressListener, AutoCloseable {
29 public ProgressDialog(JFrame parent) { 30 public ProgressDialog(JFrame parent) {
30 31
31 // init frame 32 // init frame
32 this.frame = new JFrame(Constants.NAME + " - Operation in progress"); 33 this.frame = new JFrame(String.format(I18n.translate("progress.operation"), Constants.NAME));
33 final Container pane = this.frame.getContentPane(); 34 final Container pane = this.frame.getContentPane();
34 FlowLayout layout = new FlowLayout(); 35 FlowLayout layout = new FlowLayout();
35 layout.setAlignment(FlowLayout.LEFT); 36 layout.setAlignment(FlowLayout.LEFT);
diff --git a/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java b/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java
index 1657d7b3..47f9149d 100644
--- a/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java
+++ b/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java
@@ -14,6 +14,7 @@ package cuchaz.enigma.gui.dialog;
14import com.google.common.collect.Lists; 14import com.google.common.collect.Lists;
15import cuchaz.enigma.gui.Gui; 15import cuchaz.enigma.gui.Gui;
16import cuchaz.enigma.translation.representation.entry.ClassEntry; 16import cuchaz.enigma.translation.representation.entry.ClassEntry;
17import cuchaz.enigma.utils.I18n;
17import me.xdrop.fuzzywuzzy.FuzzySearch; 18import me.xdrop.fuzzywuzzy.FuzzySearch;
18import me.xdrop.fuzzywuzzy.model.ExtractedResult; 19import me.xdrop.fuzzywuzzy.model.ExtractedResult;
19 20
@@ -45,7 +46,7 @@ public class SearchDialog {
45 } 46 }
46 47
47 public void show() { 48 public void show() {
48 frame = new JFrame("Search"); 49 frame = new JFrame(I18n.translate("menu.view.search"));
49 frame.setVisible(false); 50 frame.setVisible(false);
50 JPanel pane = new JPanel(); 51 JPanel pane = new JPanel();
51 pane.setBorder(new EmptyBorder(5, 10, 5, 10)); 52 pane.setBorder(new EmptyBorder(5, 10, 5, 10));
diff --git a/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java b/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java
index cdcad05c..50f0849f 100644
--- a/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java
+++ b/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java
@@ -7,7 +7,7 @@ import cuchaz.enigma.gui.dialog.AboutDialog;
7import cuchaz.enigma.gui.dialog.SearchDialog; 7import cuchaz.enigma.gui.dialog.SearchDialog;
8import cuchaz.enigma.gui.stats.StatsMember; 8import cuchaz.enigma.gui.stats.StatsMember;
9import cuchaz.enigma.translation.mapping.serde.MappingFormat; 9import cuchaz.enigma.translation.mapping.serde.MappingFormat;
10import cuchaz.enigma.utils.Utils; 10import cuchaz.enigma.utils.I18n;
11 11
12import javax.swing.*; 12import javax.swing.*;
13import java.awt.*; 13import java.awt.*;
@@ -40,10 +40,10 @@ public class MenuBar extends JMenuBar {
40 this.gui = gui; 40 this.gui = gui;
41 41
42 { 42 {
43 JMenu menu = new JMenu("File"); 43 JMenu menu = new JMenu(I18n.translate("menu.file"));
44 this.add(menu); 44 this.add(menu);
45 { 45 {
46 JMenuItem item = new JMenuItem("Open Jar..."); 46 JMenuItem item = new JMenuItem(I18n.translate("menu.file.jar.open"));
47 menu.add(item); 47 menu.add(item);
48 item.addActionListener(event -> { 48 item.addActionListener(event -> {
49 this.gui.jarFileChooser.setVisible(true); 49 this.gui.jarFileChooser.setVisible(true);
@@ -54,19 +54,19 @@ public class MenuBar extends JMenuBar {
54 }); 54 });
55 } 55 }
56 { 56 {
57 JMenuItem item = new JMenuItem("Close Jar"); 57 JMenuItem item = new JMenuItem(I18n.translate("menu.file.jar.close"));
58 menu.add(item); 58 menu.add(item);
59 item.addActionListener(event -> this.gui.getController().closeJar()); 59 item.addActionListener(event -> this.gui.getController().closeJar());
60 this.closeJarMenu = item; 60 this.closeJarMenu = item;
61 } 61 }
62 menu.addSeparator(); 62 menu.addSeparator();
63 JMenu openMenu = new JMenu("Open Mappings..."); 63 JMenu openMenu = new JMenu(I18n.translate("menu.file.mappings.open"));
64 menu.add(openMenu); 64 menu.add(openMenu);
65 { 65 {
66 openMappingsMenus = new ArrayList<>(); 66 openMappingsMenus = new ArrayList<>();
67 for (MappingFormat format : MappingFormat.values()) { 67 for (MappingFormat format : MappingFormat.values()) {
68 if (format.getReader() != null) { 68 if (format.getReader() != null) {
69 JMenuItem item = new JMenuItem(Utils.caplisiseCamelCase(format.name())); 69 JMenuItem item = new JMenuItem(I18n.translate("mapping_format." + format.name().toLowerCase(Locale.ROOT)));
70 openMenu.add(item); 70 openMenu.add(item);
71 item.addActionListener(event -> { 71 item.addActionListener(event -> {
72 if (this.gui.enigmaMappingsFileChooser.showOpenDialog(this.gui.getFrame()) == JFileChooser.APPROVE_OPTION) { 72 if (this.gui.enigmaMappingsFileChooser.showOpenDialog(this.gui.getFrame()) == JFileChooser.APPROVE_OPTION) {
@@ -79,7 +79,7 @@ public class MenuBar extends JMenuBar {
79 } 79 }
80 } 80 }
81 { 81 {
82 JMenuItem item = new JMenuItem("Save Mappings"); 82 JMenuItem item = new JMenuItem(I18n.translate("menu.file.mappings.save"));
83 menu.add(item); 83 menu.add(item);
84 item.addActionListener(event -> { 84 item.addActionListener(event -> {
85 this.gui.getController().saveMappings(this.gui.enigmaMappingsFileChooser.getSelectedFile().toPath()); 85 this.gui.getController().saveMappings(this.gui.enigmaMappingsFileChooser.getSelectedFile().toPath());
@@ -87,13 +87,13 @@ public class MenuBar extends JMenuBar {
87 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK)); 87 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK));
88 this.saveMappingsMenu = item; 88 this.saveMappingsMenu = item;
89 } 89 }
90 JMenu saveMenu = new JMenu("Save Mappings As..."); 90 JMenu saveMenu = new JMenu(I18n.translate("menu.file.mappings.save_as"));
91 menu.add(saveMenu); 91 menu.add(saveMenu);
92 { 92 {
93 saveMappingsMenus = new ArrayList<>(); 93 saveMappingsMenus = new ArrayList<>();
94 for (MappingFormat format : MappingFormat.values()) { 94 for (MappingFormat format : MappingFormat.values()) {
95 if (format.getWriter() != null) { 95 if (format.getWriter() != null) {
96 JMenuItem item = new JMenuItem(Utils.caplisiseCamelCase(format.name())); 96 JMenuItem item = new JMenuItem(I18n.translate("mapping_format." + format.name().toLowerCase(Locale.ROOT)));
97 saveMenu.add(item); 97 saveMenu.add(item);
98 item.addActionListener(event -> { 98 item.addActionListener(event -> {
99 // TODO: Use a specific file chooser for it 99 // TODO: Use a specific file chooser for it
@@ -107,7 +107,7 @@ public class MenuBar extends JMenuBar {
107 } 107 }
108 } 108 }
109 { 109 {
110 JMenuItem item = new JMenuItem("Close Mappings"); 110 JMenuItem item = new JMenuItem(I18n.translate("menu.file.mappings.close"));
111 menu.add(item); 111 menu.add(item);
112 item.addActionListener(event -> { 112 item.addActionListener(event -> {
113 if (this.gui.getController().isDirty()) { 113 if (this.gui.getController().isDirty()) {
@@ -118,7 +118,7 @@ public class MenuBar extends JMenuBar {
118 } else if (response == JOptionPane.NO_OPTION) 118 } else if (response == JOptionPane.NO_OPTION)
119 this.gui.getController().closeMappings(); 119 this.gui.getController().closeMappings();
120 return null; 120 return null;
121 }), "Save and close", "Discard changes", "Cancel"); 121 }), I18n.translate("prompt.close.save"), I18n.translate("prompt.close.discard"), I18n.translate("prompt.close.cancel"));
122 } else 122 } else
123 this.gui.getController().closeMappings(); 123 this.gui.getController().closeMappings();
124 124
@@ -126,14 +126,14 @@ public class MenuBar extends JMenuBar {
126 this.closeMappingsMenu = item; 126 this.closeMappingsMenu = item;
127 } 127 }
128 { 128 {
129 JMenuItem item = new JMenuItem("Drop Invalid Mappings"); 129 JMenuItem item = new JMenuItem(I18n.translate("menu.file.mappings.drop"));
130 menu.add(item); 130 menu.add(item);
131 item.addActionListener(event -> this.gui.getController().dropMappings()); 131 item.addActionListener(event -> this.gui.getController().dropMappings());
132 this.dropMappingsMenu = item; 132 this.dropMappingsMenu = item;
133 } 133 }
134 menu.addSeparator(); 134 menu.addSeparator();
135 { 135 {
136 JMenuItem item = new JMenuItem("Export Source..."); 136 JMenuItem item = new JMenuItem(I18n.translate("menu.file.export.source"));
137 menu.add(item); 137 menu.add(item);
138 item.addActionListener(event -> { 138 item.addActionListener(event -> {
139 if (this.gui.exportSourceFileChooser.showSaveDialog(this.gui.getFrame()) == JFileChooser.APPROVE_OPTION) { 139 if (this.gui.exportSourceFileChooser.showSaveDialog(this.gui.getFrame()) == JFileChooser.APPROVE_OPTION) {
@@ -143,7 +143,7 @@ public class MenuBar extends JMenuBar {
143 this.exportSourceMenu = item; 143 this.exportSourceMenu = item;
144 } 144 }
145 { 145 {
146 JMenuItem item = new JMenuItem("Export Jar..."); 146 JMenuItem item = new JMenuItem(I18n.translate("menu.file.export.jar"));
147 menu.add(item); 147 menu.add(item);
148 item.addActionListener(event -> { 148 item.addActionListener(event -> {
149 this.gui.exportJarFileChooser.setVisible(true); 149 this.gui.exportJarFileChooser.setVisible(true);
@@ -156,22 +156,22 @@ public class MenuBar extends JMenuBar {
156 } 156 }
157 menu.addSeparator(); 157 menu.addSeparator();
158 { 158 {
159 JMenuItem stats = new JMenuItem("Mapping Stats..."); 159 JMenuItem stats = new JMenuItem(I18n.translate("menu.file.stats"));
160 160
161 stats.addActionListener(event -> { 161 stats.addActionListener(event -> {
162 JFrame frame = new JFrame("Choose Included Members"); 162 JFrame frame = new JFrame(I18n.translate("menu.file.stats.title"));
163 Container pane = frame.getContentPane(); 163 Container pane = frame.getContentPane();
164 pane.setLayout(new FlowLayout()); 164 pane.setLayout(new FlowLayout());
165 165
166 Map<StatsMember, JCheckBox> checkboxes = Arrays 166 Map<StatsMember, JCheckBox> checkboxes = Arrays
167 .stream(StatsMember.values()) 167 .stream(StatsMember.values())
168 .collect(Collectors.toMap(m -> m, m -> { 168 .collect(Collectors.toMap(m -> m, m -> {
169 JCheckBox checkbox = new JCheckBox(Utils.caplisiseCamelCase(m.name())); 169 JCheckBox checkbox = new JCheckBox(I18n.translate("type." + m.name().toLowerCase(Locale.ROOT)));
170 pane.add(checkbox); 170 pane.add(checkbox);
171 return checkbox; 171 return checkbox;
172 })); 172 }));
173 173
174 JButton button = new JButton("Generate Stats"); 174 JButton button = new JButton(I18n.translate("menu.file.stats.generate"));
175 175
176 button.addActionListener(e -> { 176 button.addActionListener(e -> {
177 Set<StatsMember> includedMembers = checkboxes 177 Set<StatsMember> includedMembers = checkboxes
@@ -195,24 +195,53 @@ public class MenuBar extends JMenuBar {
195 } 195 }
196 menu.addSeparator(); 196 menu.addSeparator();
197 { 197 {
198 JMenuItem item = new JMenuItem("Exit"); 198 JMenuItem item = new JMenuItem(I18n.translate("menu.file.exit"));
199 menu.add(item); 199 menu.add(item);
200 item.addActionListener(event -> this.gui.close()); 200 item.addActionListener(event -> this.gui.close());
201 } 201 }
202 } 202 }
203 { 203 {
204 JMenu menu = new JMenu("View"); 204 JMenu menu = new JMenu(I18n.translate("menu.view"));
205 this.add(menu); 205 this.add(menu);
206 { 206 {
207 JMenu themes = new JMenu("Themes"); 207 JMenu themes = new JMenu(I18n.translate("menu.view.themes"));
208 menu.add(themes); 208 menu.add(themes);
209 for (Config.LookAndFeel lookAndFeel : Config.LookAndFeel.values()) { 209 for (Config.LookAndFeel lookAndFeel : Config.LookAndFeel.values()) {
210 JMenuItem theme = new JMenuItem(lookAndFeel.getName()); 210 JMenuItem theme = new JMenuItem(I18n.translate("menu.view.themes." + lookAndFeel.name().toLowerCase(Locale.ROOT)));
211 themes.add(theme); 211 themes.add(theme);
212 theme.addActionListener(event -> Themes.setLookAndFeel(gui, lookAndFeel)); 212 theme.addActionListener(event -> Themes.setLookAndFeel(gui, lookAndFeel));
213 } 213 }
214
215 JMenu languages = new JMenu(I18n.translate("menu.view.languages"));
216 menu.add(languages);
217 for (String lang : I18n.getAvailableLanguages()) {
218 JMenuItem language = new JMenuItem(I18n.getLanguageName(lang));
219 languages.add(language);
220 language.addActionListener(event -> I18n.setLanguage(lang));
221 language.addActionListener(event -> {
222 JFrame frame = new JFrame(I18n.translate("menu.view.languages.title"));
223 Container pane = frame.getContentPane();
224 pane.setLayout(new FlowLayout());
225
226 JLabel text = new JLabel((I18n.translate("menu.view.languages.summary")));
227 text.setHorizontalAlignment(JLabel.CENTER);
228 pane.add(text);
229
230 JButton okButton = new JButton(I18n.translate("menu.view.languages.ok"));
231 okButton.setAlignmentX(JButton.CENTER_ALIGNMENT);
232 okButton.setHorizontalAlignment(JButton.CENTER);
233 pane.add(okButton);
234 okButton.addActionListener(arg0 -> frame.dispose());
235
236 frame.setSize(350, 110);
237 frame.setResizable(false);
238 frame.setLocationRelativeTo(this.gui.getFrame());
239 frame.setVisible(true);
240 frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
241 });
242 }
214 243
215 JMenuItem search = new JMenuItem("Search"); 244 JMenuItem search = new JMenuItem(I18n.translate("menu.view.search"));
216 search.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.SHIFT_MASK)); 245 search.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.SHIFT_MASK));
217 menu.add(search); 246 menu.add(search);
218 search.addActionListener(event -> { 247 search.addActionListener(event -> {
@@ -224,15 +253,15 @@ public class MenuBar extends JMenuBar {
224 } 253 }
225 } 254 }
226 { 255 {
227 JMenu menu = new JMenu("Help"); 256 JMenu menu = new JMenu(I18n.translate("menu.help"));
228 this.add(menu); 257 this.add(menu);
229 { 258 {
230 JMenuItem item = new JMenuItem("About"); 259 JMenuItem item = new JMenuItem(I18n.translate("menu.help.about"));
231 menu.add(item); 260 menu.add(item);
232 item.addActionListener(event -> AboutDialog.show(this.gui.getFrame())); 261 item.addActionListener(event -> AboutDialog.show(this.gui.getFrame()));
233 } 262 }
234 { 263 {
235 JMenuItem item = new JMenuItem("GitHub Page"); 264 JMenuItem item = new JMenuItem(I18n.translate("menu.help.github"));
236 menu.add(item); 265 menu.add(item);
237 item.addActionListener(event -> { 266 item.addActionListener(event -> {
238 try { 267 try {
diff --git a/src/main/java/cuchaz/enigma/gui/elements/PopupMenuBar.java b/src/main/java/cuchaz/enigma/gui/elements/PopupMenuBar.java
index b9d459f3..b0fb2b04 100644
--- a/src/main/java/cuchaz/enigma/gui/elements/PopupMenuBar.java
+++ b/src/main/java/cuchaz/enigma/gui/elements/PopupMenuBar.java
@@ -1,6 +1,7 @@
1package cuchaz.enigma.gui.elements; 1package cuchaz.enigma.gui.elements;
2 2
3import cuchaz.enigma.gui.Gui; 3import cuchaz.enigma.gui.Gui;
4import cuchaz.enigma.utils.I18n;
4 5
5import javax.swing.*; 6import javax.swing.*;
6import java.awt.event.InputEvent; 7import java.awt.event.InputEvent;
@@ -21,7 +22,7 @@ public class PopupMenuBar extends JPopupMenu {
21 22
22 public PopupMenuBar(Gui gui) { 23 public PopupMenuBar(Gui gui) {
23 { 24 {
24 JMenuItem menu = new JMenuItem("Rename"); 25 JMenuItem menu = new JMenuItem(I18n.translate("popup_menu.rename"));
25 menu.addActionListener(event -> gui.startRename()); 26 menu.addActionListener(event -> gui.startRename());
26 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0)); 27 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0));
27 menu.setEnabled(false); 28 menu.setEnabled(false);
@@ -29,7 +30,7 @@ public class PopupMenuBar extends JPopupMenu {
29 this.renameMenu = menu; 30 this.renameMenu = menu;
30 } 31 }
31 { 32 {
32 JMenuItem menu = new JMenuItem("Edit Javadoc"); 33 JMenuItem menu = new JMenuItem(I18n.translate("popup_menu.javadoc"));
33 menu.addActionListener(event -> gui.startDocChange()); 34 menu.addActionListener(event -> gui.startDocChange());
34 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0)); 35 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0));
35 menu.setEnabled(false); 36 menu.setEnabled(false);
@@ -37,7 +38,7 @@ public class PopupMenuBar extends JPopupMenu {
37 this.editJavadocMenu = menu; 38 this.editJavadocMenu = menu;
38 } 39 }
39 { 40 {
40 JMenuItem menu = new JMenuItem("Show Inheritance"); 41 JMenuItem menu = new JMenuItem(I18n.translate("popup_menu.inheritance"));
41 menu.addActionListener(event -> gui.showInheritance()); 42 menu.addActionListener(event -> gui.showInheritance());
42 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, 0)); 43 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, 0));
43 menu.setEnabled(false); 44 menu.setEnabled(false);
@@ -45,7 +46,7 @@ public class PopupMenuBar extends JPopupMenu {
45 this.showInheritanceMenu = menu; 46 this.showInheritanceMenu = menu;
46 } 47 }
47 { 48 {
48 JMenuItem menu = new JMenuItem("Show Implementations"); 49 JMenuItem menu = new JMenuItem(I18n.translate("popup_menu.implementations"));
49 menu.addActionListener(event -> gui.showImplementations()); 50 menu.addActionListener(event -> gui.showImplementations());
50 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, 0)); 51 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, 0));
51 menu.setEnabled(false); 52 menu.setEnabled(false);
@@ -53,7 +54,7 @@ public class PopupMenuBar extends JPopupMenu {
53 this.showImplementationsMenu = menu; 54 this.showImplementationsMenu = menu;
54 } 55 }
55 { 56 {
56 JMenuItem menu = new JMenuItem("Show Calls"); 57 JMenuItem menu = new JMenuItem(I18n.translate("popup_menu.calls"));
57 menu.addActionListener(event -> gui.showCalls(true)); 58 menu.addActionListener(event -> gui.showCalls(true));
58 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, 0)); 59 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, 0));
59 menu.setEnabled(false); 60 menu.setEnabled(false);
@@ -61,7 +62,7 @@ public class PopupMenuBar extends JPopupMenu {
61 this.showCallsMenu = menu; 62 this.showCallsMenu = menu;
62 } 63 }
63 { 64 {
64 JMenuItem menu = new JMenuItem("Show Calls (Specific)"); 65 JMenuItem menu = new JMenuItem(I18n.translate("popup_menu.calls.specific"));
65 menu.addActionListener(event -> gui.showCalls(false)); 66 menu.addActionListener(event -> gui.showCalls(false));
66 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.SHIFT_DOWN_MASK)); 67 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.SHIFT_DOWN_MASK));
67 menu.setEnabled(false); 68 menu.setEnabled(false);
@@ -69,7 +70,7 @@ public class PopupMenuBar extends JPopupMenu {
69 this.showCallsSpecificMenu = menu; 70 this.showCallsSpecificMenu = menu;
70 } 71 }
71 { 72 {
72 JMenuItem menu = new JMenuItem("Go to Declaration"); 73 JMenuItem menu = new JMenuItem(I18n.translate("popup_menu.declaration"));
73 menu.addActionListener(event -> gui.getController().navigateTo(gui.cursorReference.entry)); 74 menu.addActionListener(event -> gui.getController().navigateTo(gui.cursorReference.entry));
74 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, 0)); 75 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, 0));
75 menu.setEnabled(false); 76 menu.setEnabled(false);
@@ -77,7 +78,7 @@ public class PopupMenuBar extends JPopupMenu {
77 this.openEntryMenu = menu; 78 this.openEntryMenu = menu;
78 } 79 }
79 { 80 {
80 JMenuItem menu = new JMenuItem("Go back"); 81 JMenuItem menu = new JMenuItem(I18n.translate("popup_menu.back"));
81 menu.addActionListener(event -> gui.getController().openPreviousReference()); 82 menu.addActionListener(event -> gui.getController().openPreviousReference());
82 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, 0)); 83 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, 0));
83 menu.setEnabled(false); 84 menu.setEnabled(false);
@@ -85,7 +86,7 @@ public class PopupMenuBar extends JPopupMenu {
85 this.openPreviousMenu = menu; 86 this.openPreviousMenu = menu;
86 } 87 }
87 { 88 {
88 JMenuItem menu = new JMenuItem("Go forward"); 89 JMenuItem menu = new JMenuItem(I18n.translate("popup_menu.forward"));
89 menu.addActionListener(event -> gui.getController().openNextReference()); 90 menu.addActionListener(event -> gui.getController().openNextReference());
90 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, 0)); 91 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, 0));
91 menu.setEnabled(false); 92 menu.setEnabled(false);
@@ -93,7 +94,7 @@ public class PopupMenuBar extends JPopupMenu {
93 this.openNextMenu = menu; 94 this.openNextMenu = menu;
94 } 95 }
95 { 96 {
96 JMenuItem menu = new JMenuItem("Mark as deobfuscated"); 97 JMenuItem menu = new JMenuItem(I18n.translate("popup_menu.mark_deobfuscated"));
97 menu.addActionListener(event -> gui.toggleMapping()); 98 menu.addActionListener(event -> gui.toggleMapping());
98 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, 0)); 99 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, 0));
99 menu.setEnabled(false); 100 menu.setEnabled(false);
diff --git a/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java b/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java
index 2a4e2d74..c24226b3 100644
--- a/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java
+++ b/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java
@@ -2,6 +2,7 @@ package cuchaz.enigma.gui.panels;
2 2
3import cuchaz.enigma.gui.ClassSelector; 3import cuchaz.enigma.gui.ClassSelector;
4import cuchaz.enigma.gui.Gui; 4import cuchaz.enigma.gui.Gui;
5import cuchaz.enigma.utils.I18n;
5 6
6import javax.swing.*; 7import javax.swing.*;
7import java.awt.*; 8import java.awt.*;
@@ -19,7 +20,7 @@ public class PanelDeobf extends JPanel {
19 this.deobfClasses.setRenameSelectionListener(gui::onPanelRename); 20 this.deobfClasses.setRenameSelectionListener(gui::onPanelRename);
20 21
21 this.setLayout(new BorderLayout()); 22 this.setLayout(new BorderLayout());
22 this.add(new JLabel("De-obfuscated Classes"), BorderLayout.NORTH); 23 this.add(new JLabel(I18n.translate("info_panel.classes.deobfuscated")), BorderLayout.NORTH);
23 this.add(new JScrollPane(this.deobfClasses), BorderLayout.CENTER); 24 this.add(new JScrollPane(this.deobfClasses), BorderLayout.CENTER);
24 } 25 }
25} 26}
diff --git a/src/main/java/cuchaz/enigma/gui/panels/PanelIdentifier.java b/src/main/java/cuchaz/enigma/gui/panels/PanelIdentifier.java
index 1bf68879..0cca40d9 100644
--- a/src/main/java/cuchaz/enigma/gui/panels/PanelIdentifier.java
+++ b/src/main/java/cuchaz/enigma/gui/panels/PanelIdentifier.java
@@ -1,6 +1,7 @@
1package cuchaz.enigma.gui.panels; 1package cuchaz.enigma.gui.panels;
2 2
3import cuchaz.enigma.gui.Gui; 3import cuchaz.enigma.gui.Gui;
4import cuchaz.enigma.utils.I18n;
4import cuchaz.enigma.utils.Utils; 5import cuchaz.enigma.utils.Utils;
5 6
6import javax.swing.*; 7import javax.swing.*;
@@ -15,12 +16,12 @@ public class PanelIdentifier extends JPanel {
15 16
16 this.setLayout(new GridLayout(4, 1, 0, 0)); 17 this.setLayout(new GridLayout(4, 1, 0, 0));
17 this.setPreferredSize(new Dimension(0, 100)); 18 this.setPreferredSize(new Dimension(0, 100));
18 this.setBorder(BorderFactory.createTitledBorder("Identifier Info")); 19 this.setBorder(BorderFactory.createTitledBorder(I18n.translate("info_panel.identifier")));
19 } 20 }
20 21
21 public void clearReference() { 22 public void clearReference() {
22 this.removeAll(); 23 this.removeAll();
23 JLabel label = new JLabel("No identifier selected"); 24 JLabel label = new JLabel(I18n.translate("info_panel.identifier.none"));
24 Utils.unboldLabel(label); 25 Utils.unboldLabel(label);
25 label.setHorizontalAlignment(JLabel.CENTER); 26 label.setHorizontalAlignment(JLabel.CENTER);
26 this.add(label); 27 this.add(label);
diff --git a/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java b/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java
index 8ee564b5..dd7f9f97 100644
--- a/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java
+++ b/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java
@@ -3,6 +3,7 @@ package cuchaz.enigma.gui.panels;
3import cuchaz.enigma.gui.ClassSelector; 3import cuchaz.enigma.gui.ClassSelector;
4import cuchaz.enigma.gui.Gui; 4import cuchaz.enigma.gui.Gui;
5import cuchaz.enigma.translation.representation.entry.ClassEntry; 5import cuchaz.enigma.translation.representation.entry.ClassEntry;
6import cuchaz.enigma.utils.I18n;
6 7
7import javax.swing.*; 8import javax.swing.*;
8import java.awt.*; 9import java.awt.*;
@@ -30,7 +31,7 @@ public class PanelObf extends JPanel {
30 this.obfClasses.setRenameSelectionListener(gui::onPanelRename); 31 this.obfClasses.setRenameSelectionListener(gui::onPanelRename);
31 32
32 this.setLayout(new BorderLayout()); 33 this.setLayout(new BorderLayout());
33 this.add(new JLabel("Obfuscated Classes"), BorderLayout.NORTH); 34 this.add(new JLabel(I18n.translate("info_panel.classes.obfuscated")), BorderLayout.NORTH);
34 this.add(new JScrollPane(this.obfClasses), BorderLayout.CENTER); 35 this.add(new JScrollPane(this.obfClasses), BorderLayout.CENTER);
35 } 36 }
36} 37}
diff --git a/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java b/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java
index a6e465d3..e7835304 100644
--- a/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java
+++ b/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java
@@ -11,6 +11,7 @@ import cuchaz.enigma.translation.mapping.EntryResolver;
11import cuchaz.enigma.translation.mapping.ResolutionStrategy; 11import cuchaz.enigma.translation.mapping.ResolutionStrategy;
12import cuchaz.enigma.translation.representation.TypeDescriptor; 12import cuchaz.enigma.translation.representation.TypeDescriptor;
13import cuchaz.enigma.translation.representation.entry.*; 13import cuchaz.enigma.translation.representation.entry.*;
14import cuchaz.enigma.utils.I18n;
14 15
15import java.util.*; 16import java.util.*;
16 17
@@ -45,14 +46,14 @@ public class StatsGenerator {
45 totalWork += entryIndex.getClasses().size(); 46 totalWork += entryIndex.getClasses().size();
46 } 47 }
47 48
48 progress.init(totalWork, "Generating stats"); 49 progress.init(totalWork, I18n.translate("progress.stats"));
49 50
50 Map<String, Integer> counts = new HashMap<>(); 51 Map<String, Integer> counts = new HashMap<>();
51 52
52 int numDone = 0; 53 int numDone = 0;
53 if (includedMembers.contains(StatsMember.METHODS) || includedMembers.contains(StatsMember.PARAMETERS)) { 54 if (includedMembers.contains(StatsMember.METHODS) || includedMembers.contains(StatsMember.PARAMETERS)) {
54 for (MethodEntry method : entryIndex.getMethods()) { 55 for (MethodEntry method : entryIndex.getMethods()) {
55 progress.step(numDone++, "Methods"); 56 progress.step(numDone++, I18n.translate("type.methods"));
56 MethodEntry root = entryResolver 57 MethodEntry root = entryResolver
57 .resolveEntry(method, ResolutionStrategy.RESOLVE_ROOT) 58 .resolveEntry(method, ResolutionStrategy.RESOLVE_ROOT)
58 .stream() 59 .stream()
@@ -77,19 +78,19 @@ public class StatsGenerator {
77 78
78 if (includedMembers.contains(StatsMember.FIELDS)) { 79 if (includedMembers.contains(StatsMember.FIELDS)) {
79 for (FieldEntry field : entryIndex.getFields()) { 80 for (FieldEntry field : entryIndex.getFields()) {
80 progress.step(numDone++, "Fields"); 81 progress.step(numDone++, I18n.translate("type.fields"));
81 update(counts, field); 82 update(counts, field);
82 } 83 }
83 } 84 }
84 85
85 if (includedMembers.contains(StatsMember.CLASSES)) { 86 if (includedMembers.contains(StatsMember.CLASSES)) {
86 for (ClassEntry clazz : entryIndex.getClasses()) { 87 for (ClassEntry clazz : entryIndex.getClasses()) {
87 progress.step(numDone++, "Classes"); 88 progress.step(numDone++, I18n.translate("type.classes"));
88 update(counts, clazz); 89 update(counts, clazz);
89 } 90 }
90 } 91 }
91 92
92 progress.step(-1, "Generating data"); 93 progress.step(-1, I18n.translate("progress.stats.data"));
93 94
94 Tree<Integer> tree = new Tree<>(); 95 Tree<Integer> tree = new Tree<>();
95 96
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsReader.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsReader.java
index 5e49a2a4..60ce587d 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsReader.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsReader.java
@@ -12,6 +12,7 @@ import cuchaz.enigma.translation.mapping.tree.HashEntryTree;
12import cuchaz.enigma.translation.representation.MethodDescriptor; 12import cuchaz.enigma.translation.representation.MethodDescriptor;
13import cuchaz.enigma.translation.representation.TypeDescriptor; 13import cuchaz.enigma.translation.representation.TypeDescriptor;
14import cuchaz.enigma.translation.representation.entry.*; 14import cuchaz.enigma.translation.representation.entry.*;
15import cuchaz.enigma.utils.I18n;
15 16
16import javax.annotation.Nullable; 17import javax.annotation.Nullable;
17import java.io.IOException; 18import java.io.IOException;
@@ -28,12 +29,12 @@ public enum EnigmaMappingsReader implements MappingsReader {
28 FILE { 29 FILE {
29 @Override 30 @Override
30 public EntryTree<EntryMapping> read(Path path, ProgressListener progress, MappingSaveParameters saveParameters) throws IOException, MappingParseException { 31 public EntryTree<EntryMapping> read(Path path, ProgressListener progress, MappingSaveParameters saveParameters) throws IOException, MappingParseException {
31 progress.init(1, "Loading mapping file"); 32 progress.init(1, I18n.translate("progress.mappings.enigma_file.loading"));
32 33
33 EntryTree<EntryMapping> mappings = new HashEntryTree<>(); 34 EntryTree<EntryMapping> mappings = new HashEntryTree<>();
34 readFile(path, mappings); 35 readFile(path, mappings);
35 36
36 progress.step(1, "Done!"); 37 progress.step(1, I18n.translate("progress.mappings.enigma_file.done"));
37 38
38 return mappings; 39 return mappings;
39 } 40 }
@@ -48,7 +49,7 @@ public enum EnigmaMappingsReader implements MappingsReader {
48 .filter(f -> f.toString().endsWith(".mapping")) 49 .filter(f -> f.toString().endsWith(".mapping"))
49 .collect(Collectors.toList()); 50 .collect(Collectors.toList());
50 51
51 progress.init(files.size(), "Loading mapping files"); 52 progress.init(files.size(), I18n.translate("progress.mappings.enigma_directory.loading"));
52 int step = 0; 53 int step = 0;
53 54
54 for (Path file : files) { 55 for (Path file : files) {
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java
index f490b1da..2ce1234a 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java
@@ -40,6 +40,7 @@ import cuchaz.enigma.translation.representation.entry.Entry;
40import cuchaz.enigma.translation.representation.entry.FieldEntry; 40import cuchaz.enigma.translation.representation.entry.FieldEntry;
41import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; 41import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
42import cuchaz.enigma.translation.representation.entry.MethodEntry; 42import cuchaz.enigma.translation.representation.entry.MethodEntry;
43import cuchaz.enigma.utils.I18n;
43import cuchaz.enigma.utils.LFPrintWriter; 44import cuchaz.enigma.utils.LFPrintWriter;
44 45
45public enum EnigmaMappingsWriter implements MappingsWriter { 46public enum EnigmaMappingsWriter implements MappingsWriter {
@@ -51,7 +52,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
51 .map(entry -> (ClassEntry) entry) 52 .map(entry -> (ClassEntry) entry)
52 .collect(Collectors.toList()); 53 .collect(Collectors.toList());
53 54
54 progress.init(classes.size(), "Writing classes"); 55 progress.init(classes.size(), I18n.translate("progress.mappings.enigma_file.writing"));
55 56
56 int steps = 0; 57 int steps = 0;
57 try (PrintWriter writer = new LFPrintWriter(Files.newBufferedWriter(path))) { 58 try (PrintWriter writer = new LFPrintWriter(Files.newBufferedWriter(path))) {
@@ -74,7 +75,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
74 75
75 applyDeletions(path, changedClasses, mappings, delta.getBaseMappings(), saveParameters.getFileNameFormat()); 76 applyDeletions(path, changedClasses, mappings, delta.getBaseMappings(), saveParameters.getFileNameFormat());
76 77
77 progress.init(changedClasses.size(), "Writing classes"); 78 progress.init(changedClasses.size(), I18n.translate("progress.mappings.enigma_directory.writing"));
78 79
79 AtomicInteger steps = new AtomicInteger(); 80 AtomicInteger steps = new AtomicInteger();
80 81
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/SrgMappingsWriter.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/SrgMappingsWriter.java
index 1270d515..f67f8fcd 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/serde/SrgMappingsWriter.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/SrgMappingsWriter.java
@@ -14,6 +14,7 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
14import cuchaz.enigma.translation.representation.entry.Entry; 14import cuchaz.enigma.translation.representation.entry.Entry;
15import cuchaz.enigma.translation.representation.entry.FieldEntry; 15import cuchaz.enigma.translation.representation.entry.FieldEntry;
16import cuchaz.enigma.translation.representation.entry.MethodEntry; 16import cuchaz.enigma.translation.representation.entry.MethodEntry;
17import cuchaz.enigma.utils.I18n;
17import cuchaz.enigma.utils.LFPrintWriter; 18import cuchaz.enigma.utils.LFPrintWriter;
18 19
19import java.io.IOException; 20import java.io.IOException;
@@ -45,7 +46,7 @@ public enum SrgMappingsWriter implements MappingsWriter {
45 Collection<Entry<?>> rootEntries = Lists.newArrayList(mappings).stream() 46 Collection<Entry<?>> rootEntries = Lists.newArrayList(mappings).stream()
46 .map(EntryTreeNode::getEntry) 47 .map(EntryTreeNode::getEntry)
47 .collect(Collectors.toList()); 48 .collect(Collectors.toList());
48 progress.init(rootEntries.size(), "Generating mappings"); 49 progress.init(rootEntries.size(), I18n.translate("progress.mappings.srg_file.generating"));
49 50
50 int steps = 0; 51 int steps = 0;
51 for (Entry<?> entry : sorted(rootEntries)) { 52 for (Entry<?> entry : sorted(rootEntries)) {
@@ -53,13 +54,13 @@ public enum SrgMappingsWriter implements MappingsWriter {
53 writeEntry(classLines, fieldLines, methodLines, mappings, entry); 54 writeEntry(classLines, fieldLines, methodLines, mappings, entry);
54 } 55 }
55 56
56 progress.init(3, "Writing mappings"); 57 progress.init(3, I18n.translate("progress.mappings.srg_file.writing"));
57 try (PrintWriter writer = new LFPrintWriter(Files.newBufferedWriter(path))) { 58 try (PrintWriter writer = new LFPrintWriter(Files.newBufferedWriter(path))) {
58 progress.step(0, "Classes"); 59 progress.step(0, I18n.translate("type.classes"));
59 classLines.forEach(writer::println); 60 classLines.forEach(writer::println);
60 progress.step(1, "Fields"); 61 progress.step(1, I18n.translate("type.fields"));
61 fieldLines.forEach(writer::println); 62 fieldLines.forEach(writer::println);
62 progress.step(2, "Methods"); 63 progress.step(2, I18n.translate("type.methods"));
63 methodLines.forEach(writer::println); 64 methodLines.forEach(writer::println);
64 } catch (IOException e) { 65 } catch (IOException e) {
65 e.printStackTrace(); 66 e.printStackTrace();
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsReader.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsReader.java
index aceb02f0..773c95eb 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsReader.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyMappingsReader.java
@@ -14,6 +14,7 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
14import cuchaz.enigma.translation.representation.entry.FieldEntry; 14import cuchaz.enigma.translation.representation.entry.FieldEntry;
15import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; 15import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
16import cuchaz.enigma.translation.representation.entry.MethodEntry; 16import cuchaz.enigma.translation.representation.entry.MethodEntry;
17import cuchaz.enigma.utils.I18n;
17 18
18import java.io.IOException; 19import java.io.IOException;
19import java.nio.file.Files; 20import java.nio.file.Files;
@@ -32,7 +33,7 @@ public enum TinyMappingsReader implements MappingsReader {
32 EntryTree<EntryMapping> mappings = new HashEntryTree<>(); 33 EntryTree<EntryMapping> mappings = new HashEntryTree<>();
33 lines.remove(0); 34 lines.remove(0);
34 35
35 progress.init(lines.size(), "Loading mapping file"); 36 progress.init(lines.size(), I18n.translate("progress.mappings.tiny_file.loading"));
36 37
37 for (int lineNumber = 0; lineNumber < lines.size(); lineNumber++) { 38 for (int lineNumber = 0; lineNumber < lines.size(); lineNumber++) {
38 progress.step(lineNumber, ""); 39 progress.step(lineNumber, "");
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyV2Reader.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyV2Reader.java
index c0488e93..a47143a2 100644
--- a/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyV2Reader.java
+++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/TinyV2Reader.java
@@ -14,6 +14,7 @@ import cuchaz.enigma.translation.representation.entry.Entry;
14import cuchaz.enigma.translation.representation.entry.FieldEntry; 14import cuchaz.enigma.translation.representation.entry.FieldEntry;
15import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; 15import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
16import cuchaz.enigma.translation.representation.entry.MethodEntry; 16import cuchaz.enigma.translation.representation.entry.MethodEntry;
17import cuchaz.enigma.utils.I18n;
17 18
18import java.io.IOException; 19import java.io.IOException;
19import java.nio.charset.StandardCharsets; 20import java.nio.charset.StandardCharsets;
@@ -45,7 +46,7 @@ final class TinyV2Reader implements MappingsReader {
45 private EntryTree<EntryMapping> read(Path path, List<String> lines, ProgressListener progress) throws MappingParseException { 46 private EntryTree<EntryMapping> read(Path path, List<String> lines, ProgressListener progress) throws MappingParseException {
46 EntryTree<EntryMapping> mappings = new HashEntryTree<>(); 47 EntryTree<EntryMapping> mappings = new HashEntryTree<>();
47 48
48 progress.init(lines.size(), "Loading mapping file"); 49 progress.init(lines.size(), I18n.translate("progress.mappings.tiny_v2.loading"));
49 50
50 BitSet state = new BitSet(STATE_SIZE); 51 BitSet state = new BitSet(STATE_SIZE);
51 @SuppressWarnings({"unchecked", "rawtypes"}) 52 @SuppressWarnings({"unchecked", "rawtypes"})
diff --git a/src/main/java/cuchaz/enigma/utils/I18n.java b/src/main/java/cuchaz/enigma/utils/I18n.java
new file mode 100644
index 00000000..f91c916a
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/utils/I18n.java
@@ -0,0 +1,102 @@
1package cuchaz.enigma.utils;
2
3import java.io.BufferedReader;
4import java.io.IOException;
5import java.io.InputStream;
6import java.io.InputStreamReader;
7import java.nio.charset.StandardCharsets;
8import java.util.ArrayList;
9import java.util.Collections;
10import java.util.Map;
11import java.util.stream.Stream;
12
13import com.google.common.collect.ImmutableList;
14import com.google.common.collect.Maps;
15import com.google.common.reflect.ClassPath;
16import com.google.common.reflect.ClassPath.ResourceInfo;
17import com.google.gson.Gson;
18
19import cuchaz.enigma.config.Config;
20
21public class I18n {
22 public static final String DEFAULT_LANGUAGE = "en_us";
23 private static final Gson GSON = new Gson();
24 private static Map<String, String> translations = Maps.newHashMap();
25 private static Map<String, String> defaultTranslations = Maps.newHashMap();
26 private static Map<String, String> languageNames = Maps.newHashMap();
27
28 static {
29 translations = load(Config.getInstance().language);
30 defaultTranslations = load(DEFAULT_LANGUAGE);
31 }
32
33 @SuppressWarnings("unchecked")
34 public static Map<String, String> load(String language) {
35 try (InputStream inputStream = I18n.class.getResourceAsStream("/lang/" + language + ".json")) {
36 if (inputStream != null) {
37 try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
38 return GSON.fromJson(reader, Map.class);
39 }
40 }
41 } catch (IOException e) {
42 e.printStackTrace();
43 }
44 return Collections.emptyMap();
45 }
46
47 public static String translate(String key) {
48 String value = translations.get(key);
49 if (value != null) {
50 return value;
51 }
52 value = defaultTranslations.get(key);
53 if (value != null) {
54 return value;
55 }
56 return key;
57 }
58
59 public static String getLanguageName(String language) {
60 return languageNames.get(language);
61 }
62
63 public static void setLanguage(String language) {
64 Config.getInstance().language = language;
65 try {
66 Config.getInstance().saveConfig();
67 } catch (IOException e) {
68 e.printStackTrace();
69 }
70 }
71
72 public static ArrayList<String> getAvailableLanguages() {
73 ArrayList<String> list = new ArrayList<String>();
74
75 try {
76 ImmutableList<ResourceInfo> resources = ClassPath.from(Thread.currentThread().getContextClassLoader()).getResources().asList();
77 Stream<ResourceInfo> dirStream = resources.stream();
78 dirStream.forEach(context -> {
79 String file = context.getResourceName();
80 if (file.startsWith("lang/") && file.endsWith(".json")) {
81 String fileName = file.substring(5, file.length() - 5);
82 list.add(fileName);
83 loadLanguageName(fileName);
84 }
85 });
86 } catch (IOException e) {
87 e.printStackTrace();
88 }
89 return list;
90 }
91
92 private static void loadLanguageName(String fileName) {
93 try (InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("lang/" + fileName + ".json")) {
94 try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
95 Map<?, ?> map = GSON.fromJson(reader, Map.class);
96 languageNames.put(fileName, map.get("language").toString());
97 }
98 } catch (IOException e) {
99 e.printStackTrace();
100 }
101 }
102}
diff --git a/src/main/resources/lang/en_us.json b/src/main/resources/lang/en_us.json
new file mode 100644
index 00000000..dbf3e451
--- /dev/null
+++ b/src/main/resources/lang/en_us.json
@@ -0,0 +1,115 @@
1{
2 "language": "English",
3
4 "mapping_format.enigma_file": "Enigma File",
5 "mapping_format.enigma_directory": "Enigma Directory",
6 "mapping_format.tiny_v2": "Tiny v2",
7 "mapping_format.tiny_file": "Tiny File",
8 "mapping_format.srg_file": "SRG File",
9 "mapping_format.proguard": "Proguard",
10 "type.methods": "Methods",
11 "type.fields": "Fields",
12 "type.parameters": "Parameters",
13 "type.classes": "Classes",
14
15 "menu.file": "File",
16 "menu.file.jar.open": "Open Jar...",
17 "menu.file.jar.close": "Close Jar",
18 "menu.file.mappings.open": "Open Mappings...",
19 "menu.file.mappings.save": "Save Mappings",
20 "menu.file.mappings.save_as": "Save Mappings As...",
21 "menu.file.mappings.close": "Close Mappings",
22 "menu.file.mappings.drop": "Drop Invalid Mappings",
23 "menu.file.export.source": "Export Source...",
24 "menu.file.export.jar": "Export Jar...",
25 "menu.file.stats": "Mapping Stats...",
26 "menu.file.stats.title": "Choose Included Members",
27 "menu.file.stats.generate": "Generate Stats",
28 "menu.file.exit": "Exit",
29 "menu.view": "View",
30 "menu.view.themes": "Themes",
31 "menu.view.themes.default": "Default",
32 "menu.view.themes.darcula": "Darcula",
33 "menu.view.themes.system": "System",
34 "menu.view.themes.none": "None (JVM Default)",
35 "menu.view.languages": "Languages",
36 "menu.view.languages.title": "Change language",
37 "menu.view.languages.summary": "The new language will be applied after the next restart.",
38 "menu.view.languages.ok": "Ok",
39 "menu.view.search": "Search",
40 "menu.help": "Help",
41 "menu.help.about": "About",
42 "menu.help.about.title": "%s - About",
43 "menu.help.about.ok": "Ok",
44 "menu.help.github": "Github Page",
45
46 "popup_menu.rename": "Rename",
47 "popup_menu.javadoc": "Edit Javadoc",
48 "popup_menu.inheritance": "Show Inheritance",
49 "popup_menu.implementations": "Show Implementations",
50 "popup_menu.calls": "Show Calls",
51 "popup_menu.calls.specific": "Show Calls (Specific)",
52 "popup_menu.declaration": "Go to Declaration",
53 "popup_menu.back": "Go back",
54 "popup_menu.forward": "Go forward",
55 "popup_menu.mark_deobfuscated": "Mark as deobfuscated",
56 "popup_menu.reset_obfuscated": "Reset to obfuscated",
57
58 "info_panel.classes.obfuscated": "Obfuscated Classes",
59 "info_panel.classes.deobfuscated": "De-obfuscated Classes",
60 "info_panel.identifier": "Identifier Info",
61 "info_panel.identifier.none": "No identifier selected",
62 "info_panel.identifier.variable": "Variable",
63 "info_panel.identifier.field": "Field",
64 "info_panel.identifier.method": "Method",
65 "info_panel.identifier.constructor": "Constructor",
66 "info_panel.identifier.class": "Class",
67 "info_panel.identifier.type_descriptor": "TypeDescriptor",
68 "info_panel.identifier.method_descriptor": "MethodDescriptor",
69 "info_panel.identifier.modifier": "Modifier",
70 "info_panel.identifier.index": "Index",
71 "info_panel.editor.class.decompiling": "(decompiling...)",
72 "info_panel.editor.class.not_found": "Unable to find class:",
73 "info_panel.tree.inheritance": "Inheritance",
74 "info_panel.tree.implementations": "Implementations",
75 "info_panel.tree.calls": "Call Graph",
76
77 "progress.operation": "%s - Operation in progress",
78 "progress.jar.indexing": "Indexing jar",
79 "progress.jar.indexing.entries": "Entries...",
80 "progress.jar.indexing.references": "Entry references...",
81 "progress.jar.indexing.methods": "Bridge methods...",
82 "progress.jar.indexing.process": "Processing...",
83 "progress.jar.writing": "Writing jar...",
84 "progress.sources.writing": "Writing sources...",
85 "progress.classes.deobfuscating": "Deobfuscating classes...",
86 "progress.classes.decompiling": "Decompiling classes...",
87 "progress.mappings.enigma_file.loading": "Loading mapping file",
88 "progress.mappings.enigma_file.done": "Done!",
89 "progress.mappings.enigma_file.writing": "Writing classes",
90 "progress.mappings.enigma_directory.loading": "Loading mapping files",
91 "progress.mappings.enigma_directory.writing": "Writing classes",
92 "progress.mappings.tiny_file.loading": "Loading mapping file",
93 "progress.mappings.tiny_v2.loading": "Loading mapping file",
94 "progress.mappings.srg_file.generating": "Generating mappings",
95 "progress.mappings.srg_file.writing": "Writing mappings",
96 "progress.stats": "Generating stats",
97 "progress.stats.data": "Generating data",
98
99 "javadocs.edit": "Edit Javadocs",
100 "javadocs.instruction": "Edit javadocs here.",
101 "javadocs.cancel": "Cancel",
102 "javadocs.save": "Save",
103
104 "prompt.close.title": "Save your changes?",
105 "prompt.close.summary": "Your mappings have not been saved yet. Do you want to save?",
106 "prompt.close.save": "Save and close",
107 "prompt.close.discard": "Discard changes",
108 "prompt.close.cancel": "Cancel",
109
110 "crash.title": "%s - Crash Report",
111 "crash.summary": "%s has crashed! =(",
112 "crash.ignore": "Ignore",
113 "crash.exit": "Exit",
114 "crash.exit.warning": "If you choose exit, you will lose any unsaved work."
115}
diff --git a/src/main/resources/lang/fr_fr.json b/src/main/resources/lang/fr_fr.json
new file mode 100644
index 00000000..ceac796a
--- /dev/null
+++ b/src/main/resources/lang/fr_fr.json
@@ -0,0 +1,115 @@
1{
2 "language": "Français",
3
4 "mapping_format.enigma_file": "Fichier Enigma",
5 "mapping_format.enigma_directory": "Répertoire Enigma",
6 "mapping_format.tiny_v2": "Tiny v2",
7 "mapping_format.tiny_file": "Fichier Tiny",
8 "mapping_format.srg_file": "Fichier SRG",
9 "mapping_format.proguard": "Proguard",
10 "type.methods": "Méthodes",
11 "type.fields": "Champs",
12 "type.parameters": "Paramètres",
13 "type.classes": "Classes",
14
15 "menu.file": "Fichier",
16 "menu.file.jar.open": "Ouvrir le jar...",
17 "menu.file.jar.close": "Fermer le jar",
18 "menu.file.mappings.open": "Ouvrir les mappings...",
19 "menu.file.mappings.save": "Enregistrer les mappings",
20 "menu.file.mappings.save_as": "Enregistrer les mappings sous...",
21 "menu.file.mappings.close": "Fermer les mappings",
22 "menu.file.mappings.drop": "Supprimer les mappings invalides",
23 "menu.file.export.source": "Exporter la source...",
24 "menu.file.export.jar": "Exporter le jar...",
25 "menu.file.stats": "Statistiques des mappings...",
26 "menu.file.stats.title": "Choisir les membres inclus",
27 "menu.file.stats.generate": "Générer les statistiques",
28 "menu.file.exit": "Quitter",
29 "menu.view": "Affichage",
30 "menu.view.themes": "Thèmes",
31 "menu.view.themes.default": "Par défaut",
32 "menu.view.themes.darcula": "Darcula",
33 "menu.view.themes.system": "Système",
34 "menu.view.themes.none": "Aucun (JVM par défaut)",
35 "menu.view.languages": "Langues",
36 "menu.view.languages.title": "Modifier la langue",
37 "menu.view.languages.summary": "La nouvelle langue sera appliquée lors du prochain redémarrage.",
38 "menu.view.languages.ok": "Ok",
39 "menu.view.search": "Rechercher",
40 "menu.help": "Aide",
41 "menu.help.about": "À propos",
42 "menu.help.about.title": "%s - À propos",
43 "menu.help.about.ok": "Ok",
44 "menu.help.github": "Page Github",
45
46 "popup_menu.rename": "Renommer",
47 "popup_menu.javadoc": "Éditer le Javadoc",
48 "popup_menu.inheritance": "Afficher l'héritage",
49 "popup_menu.implementations": "Afficher les implémentations",
50 "popup_menu.calls": "Afficher les appels",
51 "popup_menu.calls.specific": "Afficher les appels (spécifiques)",
52 "popup_menu.declaration": "Aller à la déclaration",
53 "popup_menu.back": "Annuler",
54 "popup_menu.forward": "Restaurer",
55 "popup_menu.mark_deobfuscated": "Marquer comme déobfusqué",
56 "popup_menu.reset_obfuscated": "Réinitialiser à obfusqué",
57
58 "info_panel.classes.obfuscated": "Classes obfusquées",
59 "info_panel.classes.deobfuscated": "Classes déobfusquées",
60 "info_panel.identifier": "Informations sur l'identifiant",
61 "info_panel.identifier.none": "Aucun identifiant sélectionné",
62 "info_panel.identifier.variable": "Variable",
63 "info_panel.identifier.field": "Champ",
64 "info_panel.identifier.method": "Méthode",
65 "info_panel.identifier.constructor": "Constructeur",
66 "info_panel.identifier.class": "Classe",
67 "info_panel.identifier.type_descriptor": "Descripteur de type",
68 "info_panel.identifier.method_descriptor": "Descripteur de méthode",
69 "info_panel.identifier.modifier": "Modificateur",
70 "info_panel.identifier.index": "Index",
71 "info_panel.editor.class.decompiling": "(décompilation...)",
72 "info_panel.editor.class.not_found": "Impossible de trouver la classe :",
73 "info_panel.tree.inheritance": "Héritage",
74 "info_panel.tree.implementations": "Implémentations",
75 "info_panel.tree.calls": "Graphique des appels",
76
77 "progress.operation": "%s - Opération en cours",
78 "progress.jar.indexing": "Indexation du jar",
79 "progress.jar.indexing.entries": "Entrées...",
80 "progress.jar.indexing.references": "Références des entrées...",
81 "progress.jar.indexing.methods": "Mise en place des méthodes...",
82 "progress.jar.indexing.process": "Traitement...",
83 "progress.jar.writing": "Écriture du jar...",
84 "progress.sources.writing": "Écriture des sources...",
85 "progress.classes.deobfuscating": "Déobfuscation des classes...",
86 "progress.classes.decompiling": "Décompilation des classes...",
87 "progress.mappings.enigma_file.loading": "Chargement du fichier de mappings",
88 "progress.mappings.enigma_file.done": "Terminé !",
89 "progress.mappings.enigma_file.writing": "Écriture des classes",
90 "progress.mappings.enigma_directory.loading": "Chargement des fichiers de mappings",
91 "progress.mappings.enigma_directory.writing": "Écriture des classes",
92 "progress.mappings.tiny_file.loading": "Chargement du fichier de mappings",
93 "progress.mappings.tiny_v2.loading": "Chargement du fichier de mappings",
94 "progress.mappings.srg_file.generating": "Génération des mappings",
95 "progress.mappings.srg_file.writing": "Écriture des mappings",
96 "progress.stats": "Génération des statistiques",
97 "progress.stats.data": "Génération des données",
98
99 "javadocs.edit": "Éditer les Javadocs",
100 "javadocs.instruction": "Éditer les Javadocs ici.",
101 "javadocs.cancel": "Annuler",
102 "javadocs.save": "Enregistrer",
103
104 "prompt.close.title": "Enregistrer les modifications ?",
105 "prompt.close.summary": "Vos mappings n'ont pas encore été enregistrés. Souhaitez-vous enregistrer ?",
106 "prompt.close.save": "Enregistrer et fermer",
107 "prompt.close.discard": "Annuler les modifications",
108 "prompt.close.cancel": "Annuler",
109
110 "crash.title": "%s - Rapport de plantage",
111 "crash.summary": "%s a planté ! =(",
112 "crash.ignore": "Ignorer",
113 "crash.exit": "Quitter",
114 "crash.exit.warning": "Si vous choisissez Quitter, vous perdrez tout travail non sauvegardé."
115}