8147515: JShell: Internationalize
authorrfield
Mon, 04 Apr 2016 10:31:20 -0700 (2016-04-04)
changeset 36990 ec0b843a7af5
parent 36782 6072af7a98be
child 36991 7f814aac1f80
8147515: JShell: Internationalize Reviewed-by: jlahoda
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties
langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java
langtools/src/jdk.jshell/share/classes/jdk/jshell/resources/l10n.properties
langtools/test/jdk/jshell/ReplToolTesting.java
langtools/test/jdk/jshell/StartOptionTest.java
langtools/test/jdk/jshell/ToolBasicTest.java
langtools/test/jdk/jshell/ToolFormatTest.java
langtools/test/jdk/jshell/ToolLocaleMessageTest.java
langtools/test/jdk/jshell/ToolReloadTest.java
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java	Wed Jul 05 21:31:37 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java	Mon Apr 04 10:31:20 2016 -0700
@@ -132,7 +132,7 @@
                     } catch (IOException ex) {
                         throw new IllegalStateException(ex);
                     }
-                    result.add("<press tab to see more>");
+                    result.add(repl.messageFormat("jshell.console.see.more"));
                     return cursor; //anchor should not be used.
                 }
 
@@ -337,7 +337,7 @@
                 fixes.add(0, new Fix() {
                     @Override
                     public String displayName() {
-                        return "Do nothing";
+                        return repl.messageFormat("jshell.console.do.nothing");
                     }
 
                     @Override
@@ -353,7 +353,7 @@
                     char2Fix.put((char) ('0' + i), fix);
                     in.println("" + i + ": " + fixes.get(i).displayName());
                 }
-                in.print("Choice: ");
+                in.print(repl.messageFormat("jshell.console.choice"));
                 in.flush();
                 int read;
 
@@ -438,7 +438,7 @@
                 return new FixResult(Collections.singletonList(new Fix() {
                     @Override
                     public String displayName() {
-                        return "Create variable";
+                        return repl.messageFormat("jshell.console.create.variable");
                     }
                     @Override
                     public void perform(ConsoleReader in) throws IOException {
@@ -472,14 +472,14 @@
                 }
                 if (res.isResolvable()) {
                     return new FixResult(Collections.emptyList(),
-                                         "\nThe identifier is resolvable in this context.");
+                            repl.messageFormat("jshell.console.resolvable"));
                 } else {
                     String error = "";
                     if (fixes.isEmpty()) {
-                        error = "\nNo candidate fully qualified names found to import.";
+                        error = repl.messageFormat("jshell.console.no.candidate");
                     }
                     if (!res.isUpToDate()) {
-                        error += "\nResults may be incomplete; try again later for complete results.";
+                        error += repl.messageFormat("jshell.console.incomplete");
                     }
                     return new FixResult(fixes, error);
                 }
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java	Wed Jul 05 21:31:37 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java	Mon Apr 04 10:31:20 2016 -0700
@@ -33,10 +33,8 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.function.Function;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import java.util.stream.Stream;
 import static java.util.stream.Collectors.joining;
 
 /**
@@ -113,22 +111,6 @@
         return new Setter(tool, at).setPrompt();
     }
 
-    public void printFeedbackHelp(JShellTool tool) {
-        new Setter(tool, null).printFeedbackHelp();
-    }
-
-    public void printFormatHelp(JShellTool tool) {
-        new Setter(tool, null).printFormatHelp();
-    }
-
-    public void printNewModeHelp(JShellTool tool) {
-        new Setter(tool, null).printNewModeHelp();
-    }
-
-    public void printPromptHelp(JShellTool tool) {
-        new Setter(tool, null).printPromptHelp();
-    }
-
     {
         for (FormatCase e : EnumSet.allOf(FormatCase.class))
             selectorMap.put(e.name().toLowerCase(Locale.US), e);
@@ -555,38 +537,18 @@
             this.at = at;
         }
 
-        void hard(String format, Object... args) {
-            tool.hard(format, args);
-        }
-
-        void hardrb(String key) {
-            tool.hardrb(key);
-        }
-
-        <E extends Enum<E>> void hardEnums(EnumSet<E> es, Function<E, String> e2s) {
-            hardPairs(es.stream(), ev -> ev.name().toLowerCase(Locale.US), e2s);
-        }
-
-        <T> void hardPairs(Stream<T> stream, Function<T, String> a, Function<T, String> b) {
-            tool.hardPairs(stream, a, b);
-        }
-
         void fluff(String format, Object... args) {
             tool.fluff(format, args);
         }
 
-        void error(String format, Object... args) {
-            tool.error(format, args);
+        void fluffmsg(String format, Object... args) {
+            tool.fluffmsg(format, args);
         }
 
-        void errorat(String format, Object... args) {
-            Object[] a2 = Arrays.copyOf(args, args.length + 1);
-            a2[args.length] = at.whole();
-            tool.error(format + " -- /set %s", a2);
-        }
-
-        void fluffRaw(String format, Object... args) {
-            tool.fluffRaw(format, args);
+        void errorat(String messageKey, Object... args) {
+            Object[] a2 = Arrays.copyOf(args, args.length + 2);
+            a2[args.length] = "/set " + at.whole();
+            tool.errormsg(messageKey, a2);
         }
 
         // For /set prompt <mode> "<prompt>" "<continuation-prompt>"
@@ -597,7 +559,7 @@
             if (valid) {
                 m.setPrompts(prompt, continuationPrompt);
             } else {
-                fluff("See '/help /set prompt' for help");
+                fluffmsg("jshell.msg.see", "/help /set prompt");
             }
             return valid;
         }
@@ -606,17 +568,17 @@
         boolean setNewMode() {
             String umode = at.next();
             if (umode == null) {
-                errorat("Expected new feedback mode");
+                errorat("jshell.err.feedback.expected.new.feedback.mode");
                 valid = false;
             }
             if (modeMap.containsKey(umode)) {
-                errorat("Expected a new feedback mode name. %s is a known feedback mode", umode);
+                errorat("jshell.err.feedback.expected.mode.name", umode);
                 valid = false;
             }
             String[] fluffOpt = at.next("command", "quiet");
             boolean fluff = fluffOpt == null || fluffOpt.length != 1 || "command".equals(fluffOpt[0]);
             if (fluffOpt != null && fluffOpt.length != 1) {
-                errorat("Specify either 'command' or 'quiet'");
+                errorat("jshell.err.feedback.command.quiet");
                 valid = false;
             }
             Mode om = null;
@@ -629,9 +591,9 @@
                         ? new Mode(umode, fluff, om)
                         : new Mode(umode, fluff);
                 modeMap.put(umode, nm);
-                fluff("Created new feedback mode: %s", nm.name);
+                fluffmsg("jshell.msg.feedback.new.mode", nm.name);
             } else {
-                fluff("See '/help /set newmode' for help");
+                fluffmsg("jshell.msg.see", "/help /set newmode");
             }
             return valid;
         }
@@ -641,9 +603,9 @@
             Mode m = nextMode();
             if (valid && m != null) {
                 mode = m;
-                fluff("Feedback mode: %s", mode.name);
+                fluffmsg("jshell.msg.feedback.mode", mode.name);
             } else {
-                fluff("See '/help /set feedback' for help");
+                fluffmsg("jshell.msg.see", "/help /set feedback");
             }
             return valid;
         }
@@ -653,7 +615,7 @@
             Mode m = nextMode();
             String field = at.next();
             if (field == null || at.isQuoted()) {
-                errorat("Expected field name missing");
+                errorat("jshell.err.feedback.expected.field");
                 valid = false;
             }
             String format = valid? nextFormat() : null;
@@ -675,7 +637,7 @@
                                 format));
                 }
             } else {
-                fluff("See '/help /set format' for help");
+                fluffmsg("jshell.msg.see", "/help /set format");
             }
             return valid;
         }
@@ -687,7 +649,7 @@
 
         Mode toMode(String umode) {
             if (umode == null) {
-                errorat("Expected a feedback mode");
+                errorat("jshell.err.feedback.expected.mode");
                 valid = false;
                 return null;
             }
@@ -705,11 +667,11 @@
             } else {
                 valid = false;
                 if (matches.length == 0) {
-                    errorat("Does not match any current feedback mode: %s", umode);
+                    errorat("jshell.err.feedback.does.not.match.mode", umode);
                 } else {
-                    errorat("Matches more then one current feedback mode: %s", umode);
+                    errorat("jshell.err.feedback.ambiguous.mode", umode);
                 }
-                fluff("The feedback mode should be one of the following:");
+                fluffmsg("jshell.msg.feedback.mode.following");
                 modeMap.keySet().stream()
                         .forEach(mk -> fluff("   %s", mk));
                 return null;
@@ -720,12 +682,12 @@
         final String nextFormat() {
             String format = at.next();
             if (format == null) {
-                errorat("Expected format missing");
+                errorat("jshell.err.feedback.expected.format");
                 valid = false;
                 return null;
             }
             if (!at.isQuoted()) {
-                errorat("Format '%s' must be quoted", format);
+                errorat("jshell.err.feedback.must.be.quoted", format);
                 valid = false;
                 return null;
             }
@@ -748,19 +710,19 @@
                         if (!as.isEmpty()) {
                             Selector<?> sel = selectorMap.get(as);
                             if (sel == null) {
-                                errorat("Not a valid selector %s in %s", as, s);
+                                errorat("jshell.err.feedback.not.a.valid.selector", as, s);
                                 valid = false;
                                 return;
                             }
                             SelectorCollector<?> collector = sel.collector(this);
                             if (lastCollector == null) {
                                 if (!collector.isEmpty()) {
-                                    errorat("Selector kind in multiple sections of selector list %s in %s", as, s);
+                                    errorat("jshell.err.feedback.multiple.sections", as, s);
                                     valid = false;
                                     return;
                                 }
                             } else if (collector != lastCollector) {
-                                errorat("Different selector kinds in same sections of selector list %s in %s", as, s);
+                                errorat("jshell.err.feedback.different.selector.kinds", as, s);
                                 valid = false;
                                 return;
                             }
@@ -771,36 +733,5 @@
                 }
             }
         }
-
-        final void printFormatHelp() {
-            hardrb("help.set.format");
-            hardrb("help.set.format.case");
-            hardEnums(EnumSet.allOf(FormatCase.class), ev -> ev.doc);
-            hardrb("help.set.format.action");
-            hardEnums(EnumSet.allOf(FormatAction.class), ev -> ev.doc);
-            hardrb("help.set.format.when");
-            hardEnums(EnumSet.allOf(FormatWhen.class), ev -> ev.doc);
-            hardrb("help.set.format.resolve");
-            hardEnums(EnumSet.allOf(FormatResolve.class), ev -> ev.doc);
-            hardrb("help.set.format.unresolved");
-            hardEnums(EnumSet.allOf(FormatUnresolved.class), ev -> ev.doc);
-            hardrb("help.set.format.errors");
-            hardEnums(EnumSet.allOf(FormatErrors.class), ev -> ev.doc);
-            hardrb("help.set.format.end");
-        }
-
-        final void printFeedbackHelp() {
-            hardrb("help.set.feedback");
-            modeMap.keySet().stream()
-                    .forEach(m -> hard("   %s", m));
-        }
-
-        final void printNewModeHelp() {
-            hardrb("help.set.newmode");
-        }
-
-        final void printPromptHelp() {
-            hardrb("help.set.prompt");
-        }
     }
 }
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Wed Jul 05 21:31:37 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Mon Apr 04 10:31:20 2016 -0700
@@ -42,6 +42,7 @@
 import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -49,6 +50,7 @@
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Scanner;
@@ -128,6 +130,7 @@
     final PrintStream userout;
     final PrintStream usererr;
     final Preferences prefs;
+    final Locale locale;
 
     final Feedback feedback = new Feedback();
 
@@ -141,11 +144,13 @@
      * @param userin code execution input (not yet functional)
      * @param userout code execution output  -- System.out.printf("hi")
      * @param usererr code execution error stream  -- System.err.printf("Oops")
+     * @param prefs preferences to use
+     * @param locale locale to use
      */
     public JShellTool(InputStream cmdin, PrintStream cmdout, PrintStream cmderr,
             PrintStream console,
             InputStream userin, PrintStream userout, PrintStream usererr,
-            Preferences prefs) {
+            Preferences prefs, Locale locale) {
         this.cmdin = cmdin;
         this.cmdout = cmdout;
         this.cmderr = cmderr;
@@ -154,6 +159,7 @@
         this.userout = userout;
         this.usererr = usererr;
         this.prefs = prefs;
+        this.locale = locale;
     }
 
     private IOContext input = null;
@@ -293,16 +299,94 @@
     }
 
     /**
+     * Add prefixing to embedded newlines in a string, leading with the normal
+     * prefix
+     *
+     * @param s the string to prefix
+     */
+    String prefix(String s) {
+        return prefix(s, feedback.getPre());
+    }
+
+    /**
+     * Add prefixing to embedded newlines in a string
+     *
+     * @param s the string to prefix
+     * @param leading the string to prepend
+     */
+    String prefix(String s, String leading) {
+        if (s == null || s.isEmpty()) {
+            return "";
+        }
+        return leading
+                + s.substring(0, s.length() - 1).replaceAll("\\R", System.getProperty("line.separator") + feedback.getPre())
+                + s.substring(s.length() - 1, s.length());
+    }
+
+    /**
      * Print using resource bundle look-up and adding prefix and postfix
      *
      * @param key the resource key
      */
     void hardrb(String key) {
-        String s = getResourceString(key);
-        String out = feedback.getPre()
-                + s.substring(0, s.length() - 1).replaceAll("\\R", "\n" + feedback.getPre())
-                + s.substring(s.length() - 1, s.length());
-        cmdout.print(out);
+        String s = prefix(getResourceString(key));
+        cmdout.println(s);
+    }
+
+    /**
+     * Format using resource bundle look-up using MessageFormat
+     *
+     * @param key the resource key
+     * @param args
+     */
+    String messageFormat(String key, Object... args) {
+        String rs = getResourceString(key);
+        return MessageFormat.format(rs, args);
+    }
+
+    /**
+     * Print using resource bundle look-up, MessageFormat, and add prefix and
+     * postfix
+     *
+     * @param key the resource key
+     * @param args
+     */
+    void hardmsg(String key, Object... args) {
+        cmdout.println(prefix(messageFormat(key, args)));
+    }
+
+    /**
+     * Print error using resource bundle look-up, MessageFormat, and add prefix
+     * and postfix
+     *
+     * @param key the resource key
+     * @param args
+     */
+    void errormsg(String key, Object... args) {
+        cmdout.println(prefix(messageFormat(key, args), feedback.getErrorPre()));
+    }
+
+    /**
+     * Print command-line error using resource bundle look-up, MessageFormat
+     *
+     * @param key the resource key
+     * @param args
+     */
+    void startmsg(String key, Object... args) {
+        cmderr.println(prefix(messageFormat(key, args), ""));
+    }
+
+    /**
+     * Print (fluff) using resource bundle look-up, MessageFormat, and add
+     * prefix and postfix
+     *
+     * @param key the resource key
+     * @param args
+     */
+    void fluffmsg(String key, Object... args) {
+        if (feedback.shouldDisplayCommandFluff() && interactive()) {
+            hardmsg(key, args);
+        }
     }
 
     <T> void hardPairs(Stream<T> stream, Function<T, String> a, Function<T, String> b) {
@@ -348,7 +432,8 @@
     public static void main(String[] args) throws Exception {
         new JShellTool(System.in, System.out, System.err, System.out,
                  new ByteArrayInputStream(new byte[0]), System.out, System.err,
-                 Preferences.userRoot().node("tool/JShell"))
+                 Preferences.userRoot().node("tool/JShell"),
+                 Locale.getDefault())
                 .start(args);
     }
 
@@ -373,12 +458,11 @@
         }
 
         for (String loadFile : loadList) {
-            cmdOpen(loadFile);
+            runFile(loadFile, "jshell");
         }
 
         if (regenerateOnDeath) {
-            hard("Welcome to JShell -- Version %s", version());
-            hard("Type /help for help");
+            hardmsg("jshell.msg.welcome", version());
         }
 
         try {
@@ -409,13 +493,13 @@
                     case "-classpath":
                     case "-cp":
                         if (cmdlineClasspath != null) {
-                            cmderr.printf("Conflicting -classpath option.\n");
+                            startmsg("jshell.err.opt.classpath.conflict");
                             return null;
                         }
                         if (ai.hasNext()) {
                             cmdlineClasspath = ai.next();
                         } else {
-                            cmderr.printf("Argument to -classpath missing.\n");
+                            startmsg("jshell.err.opt.classpath.arg");
                             return null;
                         }
                         break;
@@ -430,35 +514,23 @@
                         return null;
                     case "-startup":
                         if (cmdlineStartup != null) {
-                            cmderr.printf("Conflicting -startup or -nostartup option.\n");
+                            startmsg("jshell.err.opt.startup.conflict");
                             return null;
                         }
-                        if (ai.hasNext()) {
-                            String filename = ai.next();
-                            try {
-                                byte[] encoded = Files.readAllBytes(Paths.get(filename));
-                                cmdlineStartup = new String(encoded);
-                            } catch (AccessDeniedException e) {
-                                hard("File '%s' for start-up is not accessible.", filename);
-                            } catch (NoSuchFileException e) {
-                                hard("File '%s' for start-up is not found.", filename);
-                            } catch (Exception e) {
-                                hard("Exception while reading start-up file: %s", e);
-                            }
-                        } else {
-                            cmderr.printf("Argument to -startup missing.\n");
+                        cmdlineStartup = readFile(ai.hasNext()? ai.next() : null, "'-startup'");
+                        if (cmdlineStartup == null) {
                             return null;
                         }
                         break;
                     case "-nostartup":
                         if (cmdlineStartup != null && !cmdlineStartup.isEmpty()) {
-                            cmderr.printf("Conflicting -startup option.\n");
+                            startmsg("jshell.err.opt.startup.conflict");
                             return null;
                         }
                         cmdlineStartup = "";
                         break;
                     default:
-                        cmderr.printf("Unknown option: %s\n", arg);
+                        startmsg("jshell.err.opt.unknown", arg);
                         printUsage();
                         return null;
                 }
@@ -470,14 +542,7 @@
     }
 
     private void printUsage() {
-        rawout("Usage:   jshell <options> <load files>\n");
-        rawout("where possible options include:\n");
-        rawout("  -classpath <path>          Specify where to find user class files\n");
-        rawout("  -cp <path>                 Specify where to find user class files\n");
-        rawout("  -startup <file>            One run replacement for the start-up definitions\n");
-        rawout("  -nostartup                 Do not run the start-up definitions\n");
-        rawout("  -help                      Print a synopsis of standard options\n");
-        rawout("  -version                   Version information\n");
+        cmdout.print(getResourceString("help.usage"));
     }
 
     private void resetState() {
@@ -505,8 +570,7 @@
                 .build();
         shutdownSubscription = state.onShutdown((JShell deadState) -> {
             if (deadState == state) {
-                hard("State engine terminated.");
-                hard("Restore definitions with: /reload restore");
+                hardmsg("jshell.msg.terminated");
                 live = false;
             }
         });
@@ -539,7 +603,7 @@
         try (IOContext suin = new FileScannerIOContext(new StringReader(start))) {
             run(suin);
         } catch (Exception ex) {
-            hard("Unexpected exception reading start-up: %s\n", ex);
+            hardmsg("jshell.err.startup.unexpected.exception", ex);
         }
     }
 
@@ -604,7 +668,7 @@
                 }
             }
         } catch (IOException ex) {
-            hard("Unexpected exception: %s\n", ex);
+            errormsg("jshell.err.unexpected.exception", ex);
         } finally {
             input = oldInput;
         }
@@ -649,8 +713,8 @@
         switch (candidates.length) {
             case 0:
                 if (!rerunHistoryEntryById(cmd.substring(1))) {
-                    error("No such command or snippet id: %s", cmd);
-                    fluff("Type /help for help.");
+                    errormsg("jshell.err.no.such.command.or.snippet.id", cmd);
+                    fluffmsg("jshell.msg.help.for.help");
                 }   break;
             case 1:
                 Command command = candidates[0];
@@ -659,8 +723,9 @@
                     addToReplayHistory((command.command + " " + arg).trim());
                 }   break;
             default:
-                error("Command: %s is ambiguous: %s", cmd, Arrays.stream(candidates).map(c -> c.command).collect(Collectors.joining(", ")));
-                fluff("Type /help for help.");
+                errormsg("jshell.err.command.ambiguous", cmd,
+                        Arrays.stream(candidates).map(c -> c.command).collect(Collectors.joining(", ")));
+                fluffmsg("jshell.msg.help.for.help");
                 break;
         }
     }
@@ -686,35 +751,33 @@
 
     static final class Command {
         public final String command;
-        public final String params;
-        public final String description;
-        public final String help;
+        public final String helpKey;
         public final Function<String,Boolean> run;
         public final CompletionProvider completions;
         public final CommandKind kind;
 
         // NORMAL Commands
-        public Command(String command, String params, String description, String help,
-                Function<String,Boolean> run, CompletionProvider completions) {
-            this(command, params, description, help,
-                    run, completions, CommandKind.NORMAL);
+        public Command(String command, Function<String,Boolean> run, CompletionProvider completions) {
+            this(command, run, completions, CommandKind.NORMAL);
+        }
+
+        // Special kinds of Commands
+        public Command(String command, Function<String,Boolean> run, CompletionProvider completions, CommandKind kind) {
+            this(command, "help." + command.substring(1),
+                    run, completions, kind);
         }
 
         // Documentation pseudo-commands
-        public Command(String command, String description, String help,
-                CommandKind kind) {
-            this(command, null, description, help,
+        public Command(String command, String helpKey, CommandKind kind) {
+            this(command, helpKey,
                     arg -> { throw new IllegalStateException(); },
                     EMPTY_COMPLETION_PROVIDER,
                     kind);
         }
 
-        public Command(String command, String params, String description, String help,
-                Function<String,Boolean> run, CompletionProvider completions, CommandKind kind) {
+        public Command(String command, String helpKey, Function<String,Boolean> run, CompletionProvider completions, CommandKind kind) {
             this.command = command;
-            this.params = params;
-            this.description = description;
-            this.help = help;
+            this.helpKey = helpKey;
             this.run = run;
             this.completions = completions;
             this.kind = kind;
@@ -853,221 +916,86 @@
         };
     }
 
-    // Table of commands -- with command forms, argument kinds, help message, implementation, ...
+    // Table of commands -- with command forms, argument kinds, helpKey message, implementation, ...
 
     {
-        registerCommand(new Command("/list", "[all|start|<name or id>]", "list the source you have typed",
-                "Show the source of snippets, prefaced with the snippet id.\n\n" +
-                "/list\n" +
-                "  -- List the currently active snippets of code that you typed or read with /open\n" +
-                "/list start\n" +
-                "  -- List the automatically evaluated start-up snippets\n" +
-                "/list all\n" +
-                "  -- List all snippets including failed, overwritten, dropped, and start-up\n" +
-                "/list <name>\n" +
-                "  -- List snippets with the specified name (preference for active snippets)\n" +
-                "/list <id>\n" +
-                "  -- List the snippet with the specified snippet id\n",
+        registerCommand(new Command("/list",
                 arg -> cmdList(arg),
                 editKeywordCompletion()));
-        registerCommand(new Command("/edit", "<name or id>", "edit a source entry referenced by name or id",
-                "Edit a snippet or snippets of source in an external editor.\n" +
-                "The editor to use is set with /set editor.\n" +
-                "If no editor has been set, a simple editor will be launched.\n\n" +
-                "/edit <name>\n" +
-                "  -- Edit the snippet or snippets with the specified name (preference for active snippets)\n" +
-                "/edit <id>\n" +
-                "  -- Edit the snippet with the specified snippet id\n" +
-                "/edit\n" +
-                "  -- Edit the currently active snippets of code that you typed or read with /open\n",
+        registerCommand(new Command("/edit",
                 arg -> cmdEdit(arg),
                 editCompletion()));
-        registerCommand(new Command("/drop", "<name or id>", "delete a source entry referenced by name or id",
-                "Drop a snippet -- making it inactive.\n\n" +
-                "/drop <name>\n" +
-                "  -- Drop the snippet with the specified name\n" +
-                "/drop <id>\n" +
-                "  -- Drop the snippet with the specified snippet id\n",
+        registerCommand(new Command("/drop",
                 arg -> cmdDrop(arg),
                 editCompletion(),
                 CommandKind.REPLAY));
-        registerCommand(new Command("/save", "[all|history|start] <file>", "Save snippet source to a file.",
-                "Save the specified snippets and/or commands to the specified file.\n\n" +
-                "/save <file>\n" +
-                "  -- Save the source of current active snippets to the file\n" +
-                "/save all <file>\n" +
-                "  -- Save the source of all snippets to the file\n" +
-                "     Includes source including overwritten, failed, and start-up code\n" +
-                "/save history <file>\n" +
-                "  -- Save the sequential history of all commands and snippets entered since jshell was launched\n" +
-                "/save start <file>\n" +
-                "  -- Save the default start-up definitions to the file\n",
+        registerCommand(new Command("/save",
                 arg -> cmdSave(arg),
                 saveCompletion()));
-        registerCommand(new Command("/open", "<file>", "open a file as source input",
-                "Open a file and read its contents as snippets and commands.\n\n" +
-                "/open <file>\n" +
-                "  -- Read the specified file as jshell input.\n",
+        registerCommand(new Command("/open",
                 arg -> cmdOpen(arg),
                 FILE_COMPLETION_PROVIDER));
-        registerCommand(new Command("/vars", null, "list the declared variables and their values",
-                "List the type, name, and value of the current active jshell variables.\n",
+        registerCommand(new Command("/vars",
                 arg -> cmdVars(),
                 EMPTY_COMPLETION_PROVIDER));
-        registerCommand(new Command("/methods", null, "list the declared methods and their signatures",
-                "List the name, parameter types, and return type of the current active jshell methods.\n",
+        registerCommand(new Command("/methods",
                 arg -> cmdMethods(),
                 EMPTY_COMPLETION_PROVIDER));
-        registerCommand(new Command("/classes", null, "list the declared classes",
-                "List the current active jshell classes, interfaces, and enums.\n",
+        registerCommand(new Command("/classes",
                 arg -> cmdClasses(),
                 EMPTY_COMPLETION_PROVIDER));
-        registerCommand(new Command("/imports", null, "list the imported items",
-                "List the current active jshell imports.\n",
+        registerCommand(new Command("/imports",
                 arg -> cmdImports(),
                 EMPTY_COMPLETION_PROVIDER));
-        registerCommand(new Command("/exit", null, "exit jshell",
-                "Leave the jshell tool.  No work is saved.\n" +
-                "Save any work before using this command\n",
+        registerCommand(new Command("/exit",
                 arg -> cmdExit(),
                 EMPTY_COMPLETION_PROVIDER));
-        registerCommand(new Command("/reset", null, "reset jshell",
-                "Reset the jshell tool code and execution state:\n" +
-                "   * All entered code is lost.\n" +
-                "   * Start-up code is re-executed.\n" +
-                "   * The execution state is restarted.\n" +
-                "   * The classpath is cleared.\n" +
-                "Tool settings are maintained, as set with: /set ...\n" +
-                "Save any work before using this command\n",
+        registerCommand(new Command("/reset",
                 arg -> cmdReset(),
                 EMPTY_COMPLETION_PROVIDER));
-        registerCommand(new Command("/reload", "[restore] [quiet]", "reset and replay relevant history -- current or previous (restore)",
-                "Reset the jshell tool code and execution state then replay each\n" +
-                "jshell valid command and valid snippet in the order they were entered.\n\n" +
-                "/reload\n" +
-                "  -- Reset and replay the valid history since jshell was entered, or\n" +
-                "     a /reset, or /reload command was executed -- whichever is most\n" +
-                "     recent.\n" +
-                "/reload restore\n" +
-                "  -- Reset and replay the valid history between the previous and most\n" +
-                "     recent time that jshell was entered, or a /reset, or /reload\n" +
-                "     command was executed. This can thus be used to restore a previous\n" +
-                "     jshell tool sesson.\n" +
-                "/reload [restore] quiet\n" +
-                "  -- With the 'quiet' argument the replay is not shown.  Errors will display.\n",
+        registerCommand(new Command("/reload",
                 arg -> cmdReload(arg),
                 reloadCompletion()));
-        registerCommand(new Command("/classpath", "<path>", "add a path to the classpath",
-                "Append a additional path to the classpath.\n",
+        registerCommand(new Command("/classpath",
                 arg -> cmdClasspath(arg),
                 classPathCompletion(),
                 CommandKind.REPLAY));
-        registerCommand(new Command("/history", null, "history of what you have typed",
-                "Display the history of snippet and command input since this jshell was launched.\n",
+        registerCommand(new Command("/history",
                 arg -> cmdHistory(),
                 EMPTY_COMPLETION_PROVIDER));
-        registerCommand(new Command("/debug", null, "toggle debugging of the jshell",
-                "Display debugging information for the jshelll implementation.\n" +
-                "0: Debugging off\n" +
-                "r: Debugging on\n" +
-                "g: General debugging on\n" +
-                "f: File manager debugging on\n" +
-                "c': Completion analysis debugging on\n" +
-                "d': Dependency debugging on\n" +
-                "e': Event debugging on\n",
+        registerCommand(new Command("/debug",
                 arg -> cmdDebug(arg),
                 EMPTY_COMPLETION_PROVIDER,
                 CommandKind.HIDDEN));
-        registerCommand(new Command("/help", "[<command>|<subject>]", "get information about jshell",
-                "Display information about jshell.\n" +
-                "/help\n" +
-                "  -- List the jshell commands and help subjects.\n" +
-                "/help <command>\n" +
-                "  -- Display information about the specified comand. The slash must be included.\n" +
-                "     Only the first few letters of the command are needed -- if more than one\n" +
-                "     each will be displayed.  Example:  /help /li\n" +
-                "/help <subject>\n" +
-                "  -- Display information about the specified help subject. Example: /help intro\n",
+        registerCommand(new Command("/help",
                 arg -> cmdHelp(arg),
                 EMPTY_COMPLETION_PROVIDER));
-        registerCommand(new Command("/set", "editor|start|feedback|newmode|prompt|format ...", "set jshell configuration information",
-                "Set jshell configuration information, including:\n" +
-                "the external editor to use, the start-up definitions to use, a new feedback mode,\n" +
-                "the command prompt, the feedback mode to use, or the format of output.\n" +
-                "\n" +
-                "/set editor <command> <optional-arg>...\n" +
-                "  -- Specify the command to launch for the /edit command.\n" +
-                "     The <command> is an operating system dependent string.\n" +
-                "\n" +
-                "/set start <file>\n" +
-                "  -- The contents of the specified <file> become the default start-up snippets and commands.\n" +
-                "\n" +
-                "/set feedback <mode>\n" +
-                "  -- Set the feedback mode describing displayed feedback for entered snippets and commands.\n" +
-                "\n" +
-                "/set newmode <new-mode> [command|quiet [<old-mode>]]\n" +
-                "  -- Create a user-defined feedback mode, optionally copying from an existing mode.\n" +
-                "\n" +
-                "/set prompt <mode> \"<prompt>\" \"<continuation-prompt>\"\n" +
-                "  -- Set the displayed prompts for a given feedback mode.\n" +
-                "\n" +
-                "/set format <mode> <field> \"<format>\" <selector>...\n" +
-                "  -- Configure a feedback mode by setting the format of a field when the selector matchs.\n" +
-                "\n" +
-                "To get more information about one of these forms, use /help with the form specified.\n" +
-                "For example:   /help /set format\n",
+        registerCommand(new Command("/set",
                 arg -> cmdSet(arg),
                 new FixedCompletionProvider("format", "feedback", "prompt", "newmode", "start", "editor")));
-        registerCommand(new Command("/?", "", "get information about jshell",
-                "Display information about jshell (abbreviation for /help).\n" +
-                "/?\n" +
-                "  -- Display list of commands and help subjects.\n" +
-                "/? <command>\n" +
-                "  -- Display information about the specified comand. The slash must be included.\n" +
-                "     Only the first few letters of the command are needed -- if more than one\n" +
-                "     match, each will be displayed.  Example:  /? /li\n" +
-                "/? <subject>\n" +
-                "  -- Display information about the specified help subject. Example: /? intro\n",
+        registerCommand(new Command("/?",
+                "help.quest",
                 arg -> cmdHelp(arg),
-                EMPTY_COMPLETION_PROVIDER));
-        registerCommand(new Command("/!", "", "re-run last snippet",
-                "Reevaluate the most recently entered snippet.\n",
+                EMPTY_COMPLETION_PROVIDER,
+                CommandKind.NORMAL));
+        registerCommand(new Command("/!",
+                "help.bang",
                 arg -> cmdUseHistoryEntry(-1),
-                EMPTY_COMPLETION_PROVIDER));
+                EMPTY_COMPLETION_PROVIDER,
+                CommandKind.NORMAL));
 
         // Documentation pseudo-commands
-
-        registerCommand(new Command("/<id>", "re-run snippet by id",
-                "",
+        registerCommand(new Command("/<id>",
+                "help.id",
                 CommandKind.HELP_ONLY));
-        registerCommand(new Command("/-<n>", "re-run n-th previous snippet",
-                "",
+        registerCommand(new Command("/-<n>",
+                "help.previous",
                 CommandKind.HELP_ONLY));
-        registerCommand(new Command("intro", "An introduction to the jshell tool",
-                "The jshell tool allows you to execute Java code, getting immediate results.\n" +
-                "You can enter a Java definition (variable, method, class, etc), like:  int x = 8\n" +
-                "or a Java expression, like:  x + x\n" +
-                "or a Java statement or import.\n" +
-                "These little chunks of Java code are called 'snippets'.\n\n" +
-                "There are also jshell commands that allow you to understand and\n" +
-                "control what you are doing, like:  /list\n\n" +
-                "For a list of commands: /help",
+        registerCommand(new Command("intro",
+                "help.intro",
                 CommandKind.HELP_SUBJECT));
-        registerCommand(new Command("shortcuts", "Describe shortcuts",
-                "Supported shortcuts include:\n\n" +
-                "<tab>            -- After entering the first few letters of a Java identifier,\n" +
-                "                    a jshell command, or, in some cases, a jshell command argument,\n" +
-                "                    press the <tab> key to complete the input.\n" +
-                "                    If there is more than one completion, show possible completions.\n" +
-                "Shift-<tab>      -- After the name and open parenthesis of a method or constructor invocation,\n" +
-                "                    hold the <shift> key and press the <tab> to see a synopsis of all\n" +
-                "                    matching methods/constructors.\n" +
-                "<fix-shortcut> v -- After a complete expression, press \"<fix-shortcut> v\" to introduce a new variable\n" +
-                "                    whose type is based on the type of the expression.\n" +
-                "                    The \"<fix-shortcut>\" is either Alt-F1 or Alt-Enter, depending on the platform.\n" +
-                "<fix-shortcut> i -- After an unresolvable identifier, press \"<fix-shortcut> i\" and jshell will propose\n" +
-                "                    possible fully qualified names based on the content of the specified classpath.\n" +
-                "                    The \"<fix-shortcut>\" is either Alt-F1 or Alt-Enter, depending on the platform.\n",
+        registerCommand(new Command("shortcuts",
+                "help.shortcuts",
                 CommandKind.HELP_SUBJECT));
     }
 
@@ -1109,7 +1037,7 @@
             String cmd = code.substring(0, space);
             Command command = commands.get(cmd);
             if (command != null) {
-                return command.description;
+                return getResourceString(command.helpKey + ".summary");
             }
         }
 
@@ -1139,7 +1067,7 @@
             case "editor": {
                 String prog = at.next();
                 if (prog == null) {
-                    hard("The '/set editor' command requires a path argument");
+                    errormsg("jshell.err.set.editor.arg");
                     return false;
                 } else {
                     List<String> ed = new ArrayList<>();
@@ -1149,34 +1077,21 @@
                         ed.add(n);
                     }
                     editor = ed.toArray(new String[ed.size()]);
-                    fluff("Editor set to: %s", arg);
+                    fluffmsg("jshell.msg.set.editor.set", arg);
                     return true;
                 }
             }
             case "start": {
-                String filename = at.next();
-                if (filename == null) {
-                    hard("The '/set start' command requires a filename argument.");
+                String init = readFile(at.next(), "'/set start'");
+                if (init == null) {
+                    return false;
                 } else {
-                    try {
-                        byte[] encoded = Files.readAllBytes(toPathResolvingUserHome(filename));
-                        String init = new String(encoded);
-                        prefs.put(STARTUP_KEY, init);
-                    } catch (AccessDeniedException e) {
-                        hard("File '%s' for /set start is not accessible.", filename);
-                        return false;
-                    } catch (NoSuchFileException e) {
-                        hard("File '%s' for /set start is not found.", filename);
-                        return false;
-                    } catch (Exception e) {
-                        hard("Exception while reading start set file: %s", e);
-                        return false;
-                    }
+                    prefs.put(STARTUP_KEY, init);
+                    return true;
                 }
-                return true;
             }
             default:
-                hard("Error: Invalid /set argument: %s", which);
+                errormsg("jshell.err.arg", "/set", at.val());
                 return false;
         }
     }
@@ -1186,56 +1101,26 @@
         if (which == null) {
             return false;
         }
-        switch (which) {
-            case "format":
-                feedback.printFormatHelp(this);
-                return true;
-            case "feedback":
-                feedback.printFeedbackHelp(this);
-                return true;
-            case "newmode":
-                feedback.printNewModeHelp(this);
-                return true;
-            case "prompt":
-                feedback.printPromptHelp(this);
-                return true;
-            case "editor":
-                hard("Specify the command to launch for the /edit command.");
-                hard("");
-                hard("/set editor <command> <optional-arg>...");
-                hard("");
-                hard("The <command> is an operating system dependent string.");
-                hard("The <command> may include space-separated arguments (such as flags) -- <optional-arg>....");
-                hard("When /edit is used, the temporary file to edit will be appended as the last argument.");
-                return true;
-            case "start":
-                hard("Set the start-up configuration -- a sequence of snippets and commands read at start-up.");
-                hard("");
-                hard("/set start <file>");
-                hard("");
-                hard("The contents of the specified <file> become the default start-up snippets and commands --");
-                hard("which are run when the jshell tool is started or reset.");
-                return true;
-            default:
-                hard("Error: Invalid /set argument: %s", which);
-                return false;
-        }
+        hardrb("help.set." + which);
+        return true;
     }
 
     String setSubCommand(ArgTokenizer at) {
         String[] matches = at.next(SET_SUBCOMMANDS);
         if (matches == null) {
-            error("The /set command requires arguments. See: /help /set");
+            errormsg("jshell.err.set.arg");
             return null;
-        } else if (matches.length == 0) {
-            error("Not a valid argument to /set: %s", at.val());
-            fluff("/set is followed by one of: %s", Arrays.stream(SET_SUBCOMMANDS)
+        }
+        if (matches.length == 0) {
+            errormsg("jshell.err.arg", "/set", at.val());
+            fluffmsg("jshell.msg.use.one.of", Arrays.stream(SET_SUBCOMMANDS)
                     .collect(Collectors.joining(", "))
             );
             return null;
-        } else if (matches.length > 1) {
-            error("Ambiguous argument to /set: %s", at.val());
-            fluff("Use one of: %s", Arrays.stream(matches)
+        }
+        if (matches.length > 1) {
+            errormsg("jshell.err.set.ambiguous", at.val());
+            fluffmsg("jshell.msg.use.one.of", Arrays.stream(matches)
                     .collect(Collectors.joining(", "))
             );
             return null;
@@ -1245,11 +1130,11 @@
 
     boolean cmdClasspath(String arg) {
         if (arg.isEmpty()) {
-            hard("/classpath requires a path argument");
+            errormsg("jshell.err.classpath.arg");
             return false;
         } else {
             state.addToClasspath(toPathResolvingUserHome(arg).toString());
-            fluff("Path %s added to classpath", arg);
+            fluffmsg("jshell.msg.classpath", arg);
             return true;
         }
     }
@@ -1322,7 +1207,7 @@
                     .get();
             prefs.put(REPLAY_RESTORE_KEY, hist);
         }
-        fluff("Goodbye\n");
+        fluffmsg("jshell.msg.goodbye");
         return true;
     }
 
@@ -1344,31 +1229,24 @@
                     hard("");
                     hard("%s", c.command);
                     hard("");
-                    hard("%s", c.help.replaceAll("\n", LINE_SEP + feedback.getPre()));
+                    hardrb(c.helpKey);
                 }
                 return true;
             } else {
-                error("No commands or subjects start with the provided argument: %s\n\n", arg);
+                errormsg("jshell.err.help.arg", arg);
             }
         }
-        hard("Type a Java language expression, statement, or declaration.");
-        hard("Or type one of the following commands:");
-        hard("");
+        hardmsg("jshell.msg.help.begin");
         hardPairs(commands.values().stream()
                 .filter(cmd -> cmd.kind.showInHelp),
-                cmd -> (cmd.params != null)
-                            ? cmd.command + " " + cmd.params
-                            : cmd.command,
-                cmd -> cmd.description
+                cmd -> cmd.command + " " + getResourceString(cmd.helpKey + ".args"),
+                cmd -> getResourceString(cmd.helpKey + ".summary")
         );
-        hard("");
-        hard("For more information type '/help' followed by the name of command or a subject.");
-        hard("For example '/help /list' or '/help intro'.  Subjects:");
-        hard("");
+        hardmsg("jshell.msg.help.subject");
         hardPairs(commands.values().stream()
                 .filter(cmd -> cmd.kind == CommandKind.HELP_SUBJECT),
                 cmd -> cmd.command,
-                cmd -> cmd.description
+                cmd -> getResourceString(cmd.helpKey + ".summary")
         );
         return true;
     }
@@ -1460,28 +1338,28 @@
 
     private boolean cmdDrop(String arg) {
         if (arg.isEmpty()) {
-            hard("In the /drop argument, please specify an import, variable, method, or class to drop.");
-            hard("Specify by id or name. Use /list to see ids. Use /reset to reset all state.");
+            errormsg("jshell.err.drop.arg");
             return false;
         }
         Stream<Snippet> stream = argToSnippets(arg, false);
         if (stream == null) {
-            hard("No definition or id named %s found.  See /classes, /methods, /vars, or /list", arg);
+            errormsg("jshell.err.def.or.id.not.found", arg);
+            fluffmsg("jshell.msg.see.classes.etc");
             return false;
         }
         List<Snippet> snippets = stream
                 .filter(sn -> state.status(sn).isActive && sn instanceof PersistentSnippet)
                 .collect(toList());
         if (snippets.isEmpty()) {
-            hard("The argument did not specify an active import, variable, method, or class to drop.");
+            errormsg("jshell.err.drop.active");
             return false;
         }
         if (snippets.size() > 1) {
-            hard("The argument references more than one import, variable, method, or class.");
-            hard("Try again with one of the ids below:");
-            for (Snippet sn : snippets) {
-                cmdout.printf("%4s : %s\n", sn.id(), sn.source().replace("\n", "\n       "));
-            }
+            errormsg("jshell.err.drop.ambiguous");
+            fluffmsg("jshell.msg.use.one.of", snippets.stream()
+                    .map(sn -> String.format("\n%4s : %s", sn.id(), sn.source().replace("\n", "\n       ")))
+                    .collect(Collectors.joining(", "))
+            );
             return false;
         }
         PersistentSnippet psn = (PersistentSnippet) snippets.get(0);
@@ -1492,7 +1370,8 @@
     private boolean cmdEdit(String arg) {
         Stream<Snippet> stream = argToSnippets(arg, true);
         if (stream == null) {
-            hard("No definition or id named %s found.  See /classes, /methods, /vars, or /list", arg);
+            errormsg("jshell.err.def.or.id.not.found", arg);
+            fluffmsg("jshell.msg.see.classes.etc");
             return false;
         }
         Set<String> srcSet = new LinkedHashSet<>();
@@ -1565,7 +1444,7 @@
                     }
                     currSrcs = nextSrcs;
                 } catch (IllegalStateException ex) {
-                    hard("Resetting...");
+                    hardmsg("jshell.msg.resetting");
                     resetState();
                     currSrcs = new LinkedHashSet<>(); // re-process everything
                 }
@@ -1591,11 +1470,12 @@
         }
         Stream<Snippet> stream = argToSnippets(arg, true);
         if (stream == null) {
+            errormsg("jshell.err.def.or.id.not.found", arg);
             // Check if there are any definitions at all
             if (argToSnippets("", false).iterator().hasNext()) {
-                hard("No definition or id named %s found.  Try /list without arguments.", arg);
+                fluffmsg("jshell.msg.try.list.without.args");
             } else {
-                hard("No definition or id named %s found.  There are no active definitions.", arg);
+                hardmsg("jshell.msg.no.active");
             }
             return false;
         }
@@ -1613,26 +1493,54 @@
     }
 
     private boolean cmdOpen(String filename) {
-        if (filename.isEmpty()) {
-            hard("The /open command requires a filename argument.");
-            return false;
-        } else {
+        return runFile(filename, "'/open'");
+    }
+
+    private boolean runFile(String filename, String context) {
+        if (!filename.isEmpty()) {
             try {
                 run(new FileScannerIOContext(toPathResolvingUserHome(filename).toString()));
+                return true;
             } catch (FileNotFoundException e) {
-                hard("File '%s' is not found: %s", filename, e.getMessage());
-                return false;
+                errormsg("jshell.err.file.not.found", context, filename, e.getMessage());
             } catch (Exception e) {
-                hard("Exception while reading file: %s", e);
-                return false;
+                errormsg("jshell.err.file.exception", context, filename, e);
             }
+        } else {
+            errormsg("jshell.err.file.filename", context);
         }
-        return true;
+        return false;
+    }
+
+    /**
+     * Read an external file. Error messages accessed via keyPrefix
+     *
+     * @param filename file to access or null
+     * @param context printable non-natural language context for errors
+     * @return contents of file as string
+     */
+    String readFile(String filename, String context) {
+        if (filename != null) {
+            try {
+                byte[] encoded = Files.readAllBytes(Paths.get(filename));
+                return new String(encoded);
+            } catch (AccessDeniedException e) {
+                errormsg("jshell.err.file.not.accessible", context, filename, e.getMessage());
+            } catch (NoSuchFileException e) {
+                errormsg("jshell.err.file.not.found", context, filename, e.getMessage());
+            } catch (Exception e) {
+                errormsg("jshell.err.file.exception", context, filename, e);
+            }
+        } else {
+            errormsg("jshell.err.file.filename", context);
+        }
+        return null;
+
     }
 
     private boolean cmdReset() {
         live = false;
-        fluff("Resetting state.");
+        fluffmsg("jshell.msg.resetting.state");
         return true;
     }
 
@@ -1642,21 +1550,20 @@
         if (arg.length() > 0) {
             if ("restore".startsWith(arg)) {
                 if (replayableHistoryPrevious == null) {
-                    hard("No previous history to restore\n", arg);
+                    errormsg("jshell.err.reload.no.previous");
                     return false;
                 }
                 history = replayableHistoryPrevious;
             } else if ("quiet".startsWith(arg)) {
                 echo = false;
             } else {
-                hard("Invalid argument to reload command: %s\nUse 'restore', 'quiet', or no argument\n", arg);
+                errormsg("jshell.err.arg", "/reload", arg);
                 return false;
             }
         }
-        fluff("Restarting and restoring %s.",
-                history == replayableHistoryPrevious
-                        ? "from previous state"
-                        : "state");
+        fluffmsg(history == replayableHistoryPrevious
+                        ? "jshell.err.reload.restarting.previous.state"
+                        : "jshell.err.reload.restarting.state");
         resetState();
         run(new ReloadIOContext(history,
                 echo? cmdout : null));
@@ -1666,7 +1573,7 @@
     private boolean cmdSave(String arg_filename) {
         Matcher mat = HISTORY_ALL_START_FILENAME.matcher(arg_filename);
         if (!mat.find()) {
-            hard("Malformed argument to the /save command: %s", arg_filename);
+            errormsg("jshell.err.arg", arg_filename);
             return false;
         }
         boolean useHistory = false;
@@ -1686,7 +1593,7 @@
         }
         String filename = mat.group("filename");
         if (filename == null ||filename.isEmpty()) {
-            hard("The /save command requires a filename argument.");
+            errormsg("jshell.err.file.filename", "/save");
             return false;
         }
         try (BufferedWriter writer = Files.newBufferedWriter(toPathResolvingUserHome(filename),
@@ -1709,10 +1616,10 @@
                 }
             }
         } catch (FileNotFoundException e) {
-            hard("File '%s' for save is not accessible: %s", filename, e.getMessage());
+            errormsg("jshell.err.file.not.found", "/save", filename, e.getMessage());
             return false;
         } catch (Exception e) {
-            hard("Exception while saving: %s", e);
+            errormsg("jshell.err.file.exception", "/save", filename, e);
             return false;
         }
         return true;
@@ -1722,7 +1629,7 @@
         for (VarSnippet vk : state.variables()) {
             String val = state.status(vk) == Status.VALID
                     ? state.varValue(vk)
-                    : "(not-active)";
+                    : "jshell.msg.vars.not.active";
             hard("  %s %s = %s", vk.typeName(), vk.name(), val);
         }
         return true;
@@ -1777,7 +1684,7 @@
         if (index >= 0 && index < keys.size()) {
             rerunSnippet(keys.get(index));
         } else {
-            hard("Cannot find snippet %d", index + 1);
+            errormsg("jshell.err.out.of.range");
             return false;
         }
         return true;
@@ -1912,11 +1819,7 @@
         if (ste.causeSnippet() == null) {
             // main event
             for (Diag d : diagnostics) {
-                if (d.isError()) {
-                    hard("Error:");
-                } else {
-                    hard("Warning:");
-                }
+                hardmsg(d.isError()? "jshell.msg.error" : "jshell.msg.warning");
                 List<String> disp = new ArrayList<>();
                 displayDiagnostics(source, d, disp);
                 disp.stream()
@@ -1939,7 +1842,7 @@
                 }
             } else {
                 if (diagnostics.isEmpty()) {
-                    hard("Failed.");
+                    errormsg("jshell.err.failed");
                 }
                 return true;
             }
@@ -1975,9 +1878,9 @@
             String fileName = ste.getFileName();
             int lineNumber = ste.getLineNumber();
             String loc = ste.isNativeMethod()
-                    ? "Native Method"
+                    ? getResourceString("jshell.msg.native.method")
                     : fileName == null
-                            ? "Unknown Source"
+                            ? getResourceString("jshell.msg.unknown.source")
                             : lineNumber >= 0
                                     ? fileName + ":" + lineNumber
                                     : fileName;
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties	Wed Jul 05 21:31:37 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties	Mon Apr 04 10:31:20 2016 -0700
@@ -23,9 +23,359 @@
 # questions.
 #
 
+jshell.msg.welcome =\
+Welcome to JShell -- Version {0}\n\
+For an introduction type: /help intro\n
+jshell.err.opt.classpath.conflict = Conflicting -classpath option.
+jshell.err.opt.classpath.arg = Argument to -classpath missing.
+jshell.err.opt.startup.conflict = Conflicting -startup or -nostartup option.
+jshell.err.opt.unknown = Unknown option: {0}
+
+jshell.msg.terminated =\
+State engine terminated.\n\
+Restore definitions with: /reload restore
+
+jshell.msg.use.one.of = Use one of: {0}
+jshell.err.def.or.id.not.found = No definition or id found named: {0}
+jshell.msg.see.classes.etc = See /classes, /methods, /vars, or /list
+jshell.err.arg = Invalid ''{0}'' argument: {1}
+jshell.msg.see = See {0} for help.
+
+jshell.err.file.not.accessible = File ''{1}'' for ''{0}'' is not accessible: {2}
+jshell.err.file.not.found = File ''{1}'' for ''{0}'' is not found: {2}
+jshell.err.file.exception = File ''{1}'' for ''{0}'' threw exception: {2}
+jshell.err.file.filename = ''{0}'' requires a filename argument.
+
+jshell.err.startup.unexpected.exception = Unexpected exception reading start-up: {0}
+jshell.err.unexpected.exception = Unexpected exception: {0}
+
+jshell.err.no.such.command.or.snippet.id = No such command or snippet id: {0}
+jshell.err.command.ambiguous = Command: ''{0}'' is ambiguous: {1}
+jshell.err.set.editor.arg = The ''/set editor'' command requires a path argument
+jshell.msg.set.editor.set = Editor set to: {0}
+
+jshell.msg.try.list.without.args = Try ''/list'' without arguments.
+jshell.msg.no.active = There are no active definitions.
+
+jshell.msg.resetting = Resetting...
+jshell.msg.resetting.state = Resetting state.
+
+jshell.err.reload.no.previous = No previous history to restore
+jshell.err.reload.restarting.previous.state = Restarting and restoring from previous state.
+jshell.err.reload.restarting.state = Restarting and restoring state.
+
+jshell.msg.vars.not.active = (not-active)
+
+jshell.err.out.of.range = Out of range
+
+jshell.msg.error = Error:
+jshell.msg.warning = Warning:
+
+jshell.err.set.arg = The ''/set'' command requires a sub-command and arguments. See: ''/help /set''
+jshell.err.set.ambiguous = Ambiguous sub-command argument to ''/set'': {0}
+
+jshell.err.classpath.arg = The /classpath command requires a path argument.
+jshell.msg.classpath = Path ''{0}'' added to classpath
+
+jshell.err.help.arg = No commands or subjects start with the provided argument: {0}
+jshell.msg.help.begin =\
+Type a Java language expression, statement, or declaration.\n\
+Or type one of the following commands:\n
+jshell.msg.help.subject =\n\
+For more information type ''/help'' followed by the name of command or a subject.\n\
+For example ''/help /list'' or ''/help intro''.  Subjects:\n
+
+jshell.err.drop.arg =\
+In the /drop argument, please specify an import, variable, method, or class to drop.\n\
+Specify by id or name. Use /list to see ids. Use /reset to reset all state.
+jshell.msg.drop.not.active = The argument did not specify an active import, variable, method, or class to drop.
+jshell.err.drop.ambiguous = The argument references more than one import, variable, method, or class.
+jshell.err.failed = Failed.
+jshell.msg.native.method = Native Method
+jshell.msg.unknown.source = Unknown Source
+jshell.msg.goodbye = Goodbye
+
+jshell.msg.help.for.help = Type /help for help.
+
+jshell.err.feedback.expected.new.feedback.mode = Expected new feedback mode -- {0}
+jshell.err.feedback.expected.mode.name = Expected a new feedback mode name. ''{0}'' is a known feedback mode -- {1}
+jshell.err.feedback.command.quiet = Specify either ''command'' or ''quiet'' -- {0}
+jshell.err.feedback.expected.field = Expected field name missing -- {0}
+jshell.err.feedback.expected.mode = Expected a feedback mode -- {0}
+jshell.err.feedback.does.not.match.mode = Does not match any current feedback mode: {0} -- {1}
+jshell.err.feedback.ambiguous.mode = Matches more then one current feedback mode: {0} -- {1}
+jshell.err.feedback.expected.format = Expected format missing -- {0}
+jshell.err.feedback.must.be.quoted = Format ''{0}'' must be quoted -- {1}
+jshell.err.feedback.not.a.valid.selector = Not a valid selector ''{0}'' in ''{1}'' -- {2}
+jshell.err.feedback.multiple.sections = Selector kind in multiple sections of selector list ''{0}'' in ''{1}'' -- {2}
+jshell.err.feedback.different.selector.kinds = Different selector kinds in same sections of selector list ''{0}'' in ''{1}'' -- {2}
+
+jshell.msg.feedback.new.mode = Created new feedback mode: {0}
+jshell.msg.feedback.mode = Feedback mode: {0}
+jshell.msg.feedback.mode.following = The feedback mode should be one of the following:
+
+jshell.console.see.more = <press tab to see more>
+jshell.console.do.nothing = Do nothing
+jshell.console.choice = Choice: \
+
+jshell.console.create.variable = Create variable
+jshell.console.resolvable = \nThe identifier is resolvable in this context.
+jshell.console.no.candidate = \nNo candidate fully qualified names found to import.
+jshell.console.incomplete = \nResults may be incomplete; try again later for complete results.
+
+
+help.usage = \
+Usage:   jshell <options> <load files>\n\
+where possible options include:\n\t\
+  -classpath <path>          Specify where to find user class files\n\t\
+  -cp <path>                 Specify where to find user class files\n\t\
+  -startup <file>            One run replacement for the start-up definitions\n\t\
+  -nostartup                 Do not run the start-up definitions\n\t\
+  -help                      Print a synopsis of standard options\n\t\
+  -version                   Version information\n
+
+help.list.summary = list the source you have typed
+help.list.args = [all|start|<name or id>]
+help.list =\
+Show the source of snippets, prefaced with the snippet id.\n\
+\n\
+/list\n\t\
+    List the currently active snippets of code that you typed or read with /open\n\n\
+/list start\n\t\
+    List the automatically evaluated start-up snippets\n\n\
+/list all\n\t\
+    List all snippets including failed, overwritten, dropped, and start-up\n\n\
+/list <name>\n\t\
+    List snippets with the specified name (preference for active snippets)\n\n\
+/list <id>\n\t\
+    List the snippet with the specified snippet id
+
+help.edit.summary = edit a source entry referenced by name or id
+help.edit.args = <name or id>
+help.edit =\
+Edit a snippet or snippets of source in an external editor.\n\
+The editor to use is set with /set editor.\n\
+If no editor has been set, a simple editor will be launched.\n\
+\n\
+/edit <name>\n\t\
+    Edit the snippet or snippets with the specified name (preference for active snippets)\n\n\
+/edit <id>\n\t\
+    Edit the snippet with the specified snippet id\n\n\
+/edit\n\t\
+    Edit the currently active snippets of code that you typed or read with /open
+
+help.drop.summary = delete a source entry referenced by name or id
+help.drop.args = <name or id>
+help.drop =\
+Drop a snippet -- making it inactive.\n\
+\n\
+/drop <name>\n\t\
+    Drop the snippet with the specified name\n\n\
+/drop <id>\n\t\
+    Drop the snippet with the specified snippet id
+
+help.save.summary = Save snippet source to a file.
+help.save.args = [all|history|start] <file>
+help.save =\
+Save the specified snippets and/or commands to the specified file.\n\
+\n\
+/save <file>\n\t\
+    Save the source of current active snippets to the file.\n\n\
+/save all <file>\n\t\
+    Save the source of all snippets to the file.\n\t\
+    Includes source including overwritten, failed, and start-up code.\n\n\
+/save history <file>\n\t\
+    Save the sequential history of all commands and snippets entered since jshell was launched.\n\n\
+/save start <file>\n\t\
+    Save the default start-up definitions to the file.
+
+help.open.summary = open a file as source input
+help.open.args = <file>
+help.open =\
+Open a file and read its contents as snippets and commands.\n\
+\n\
+/open <file>\n\t\
+    Read the specified file as jshell input.
+
+help.vars.summary = list the declared variables and their values
+help.vars.args =
+help.vars =\
+List the type, name, and value of the current active jshell variables.
+
+help.methods.summary = list the declared methods and their signatures
+help.methods.args =
+help.methods =\
+List the name, parameter types, and return type of the current active jshell methods.
+
+help.classes.summary = list the declared classes
+help.classes.args =
+help.classes =\
+List the current active jshell classes, interfaces, and enums.
+
+help.imports.summary = list the imported items
+help.imports.args =
+help.imports =\
+List the current active jshell imports.
+
+help.exit.summary = exit jshell
+help.exit.args =
+help.exit =\
+Leave the jshell tool.  No work is saved.\n\
+Save any work before using this command
+
+help.reset.summary = reset jshell
+help.reset.args =
+help.reset =\
+Reset the jshell tool code and execution state:\n\t\
+   * All entered code is lost.\n\t\
+   * Start-up code is re-executed.\n\t\
+   * The execution state is restarted.\n\t\
+   * The classpath is cleared.\n\
+Tool settings are maintained, as set with: /set ...\n\
+Save any work before using this command
+
+help.reload.summary = reset and replay relevant history -- current or previous (restore)
+help.reload.args = [restore] [quiet]
+help.reload =\
+Reset the jshell tool code and execution state then replay each\n\
+jshell valid command and valid snippet in the order they were entered.\n\
+\n\
+/reload\n\t\
+     Reset and replay the valid history since jshell was entered, or\n\t\
+     a /reset, or /reload command was executed -- whichever is most\n\t\
+     recent.\n\n\
+/reload restore\n\t\
+     Reset and replay the valid history between the previous and most\n\t\
+     recent time that jshell was entered, or a /reset, or /reload\n\t\
+     command was executed. This can thus be used to restore a previous\n\t\
+     jshell tool sesson.\n\n\
+/reload [restore] quiet\n\t\
+     With the 'quiet' argument the replay is not shown.  Errors will display.
+
+help.classpath.summary = add a path to the classpath
+help.classpath.args = <path>
+help.classpath =\
+Append a additional path to the classpath.
+
+help.history.summary = history of what you have typed
+help.history.args =
+help.history =\
+Display the history of snippet and command input since this jshell was launched.
+
+help.debug.summary = toggle debugging of the jshell
+help.debug.args = [0][r][g][f][c][d][e]
+help.debug =\
+Display debugging information for the jshell implementation.\n\
+0: Debugging off\n\
+r: Tool level debugging on\n\
+g: General debugging on\n\
+f: File manager debugging on\n\
+c: Completion analysis debugging on\n\
+d: Dependency debugging on\n\
+e: Event debugging on
+
+help.help.summary = get information about jshell
+help.help.args = [<command>|<subject>]
+help.help =\
+Display information about jshell.\n\
+/help\n\t\
+     List the jshell commands and help subjects.\n\n\
+/help <command>\n\t\
+     Display information about the specified comand. The slash must be included.\n\t\
+     Only the first few letters of the command are needed -- if more than one\n\t\
+     each will be displayed.  Example:  /help /li\n\n\
+/help <subject>\n\t\
+     Display information about the specified help subject. Example: /help intro
+
+help.set.summary = set jshell configuration information
+help.set.args = editor|start|feedback|newmode|prompt|format ...
+help.set =\
+Set jshell configuration information, including:\n\
+the external editor to use, the start-up definitions to use, a new feedback mode,\n\
+the command prompt, the feedback mode to use, or the format of output.\n\
+\n\
+/set editor <command> <optional-arg>...\n\t\
+     Specify the command to launch for the /edit command.\n\t\
+     The <command> is an operating system dependent string.\n\n\
+/set start <file>\n\t\
+     The contents of the specified <file> become the default start-up snippets and commands.\n\n\
+/set feedback <mode>\n\t\
+     Set the feedback mode describing displayed feedback for entered snippets and commands.\n\n\
+/set newmode <new-mode> [command|quiet [<old-mode>]]\n\t\
+     Create a user-defined feedback mode, optionally copying from an existing mode.\n\n\
+/set prompt <mode> "<prompt>" "<continuation-prompt>"\n\t\
+     Set the displayed prompts for a given feedback mode.\n\n\
+/set format <mode> <field> "<format>" <selector>...\n\t\
+     Configure a feedback mode by setting the format of a field when the selector matchs.\n\n\
+To get more information about one of these forms, use /help with the form specified.\n\
+For example:   /help /set format
+
+help.quest.summary = get information about jshell
+help.quest.args = [<command>|<subject>]
+help.quest =\
+Display information about jshell (abbreviation for /help).\n\
+/?\n\t\
+     Display list of commands and help subjects.\n\
+/? <command>\n\t\
+     Display information about the specified comand. The slash must be included.\n\t\
+     Only the first few letters of the command are needed -- if more than one\n\t\
+     match, each will be displayed.  Example:  /? /li\n\
+/? <subject>\n\t\
+     Display information about the specified help subject. Example: /? intro
+
+help.bang.summary = re-run last snippet
+help.bang.args =
+help.bang =\
+Reevaluate the most recently entered snippet.
+
+help.id.summary = re-run snippet by id
+help.id.args =
+help.id =\
+Reevaluate the snippet specified by the id.
+
+help.previous.summary = re-run n-th previous snippet
+help.previous.args =
+help.previous =\
+Reevaluate the n-th most recently entered snippet.
+
+help.intro.summary = an introduction to the jshell tool
+help.intro =\
+The jshell tool allows you to execute Java code, getting immediate results.\n\
+You can enter a Java definition (variable, method, class, etc), like:  int x = 8\n\
+or a Java expression, like:  x + x\n\
+or a Java statement or import.\n\
+These little chunks of Java code are called 'snippets'.\n\
+\n\
+There are also jshell commands that allow you to understand and\n\
+control what you are doing, like:  /list\n\
+\n\
+For a list of commands: /help
+
+help.shortcuts.summary = a description of shortcuts
+help.shortcuts =\
+Supported shortcuts include:\n\
+\n\
+<tab>\n\t\t\
+        After entering the first few letters of a Java identifier,\n\t\t\
+        a jshell command, or, in some cases, a jshell command argument,\n\t\t\
+        press the <tab> key to complete the input.\n\t\t\
+        If there is more than one completion, show possible completions.\n\n\
+Shift-<tab>\n\t\t\
+        After the name and open parenthesis of a method or constructor invocation,\n\t\t\
+        hold the <shift> key and press the <tab> to see a synopsis of all\n\t\t\
+        matching methods/constructors.\n\n\
+<fix-shortcut> v\n\t\t\
+        After a complete expression, press "<fix-shortcut> v" to introduce a new variable\n\t\t\
+        whose type is based on the type of the expression.\n\t\t\
+        The "<fix-shortcut>" is either Alt-F1 or Alt-Enter, depending on the platform.\n\n\
+<fix-shortcut> i\n\t\t\
+        After an unresolvable identifier, press "<fix-shortcut> i" and jshell will propose\n\t\t\
+        possible fully qualified names based on the content of the specified classpath.\n\t\t\
+        The "<fix-shortcut>" is either Alt-F1 or Alt-Enter, depending on the platform.
+
 help.set.format = \
 Set the format for reporting a snippet event.\n\
-\n\
+\n\t\
 /set format <mode> <field> "<format>" <selector>...\n\
 \n\
 Where <mode> is the name of a previously defined feedback mode -- see '/help /set newmode'.\n\
@@ -56,14 +406,42 @@
 The structure of selector is a hyphen separated list of selector kind lists.\n\
 A selector kind list is a comma separated list of values of one selector kind.\n\
 A selector matches if each selector kind list matches; A selector kind list\n\
-matches if one of the values matches.\n
-help.set.format.case = The case selector kind describes the kind of snippet.  The values are:\n
-help.set.format.action = The action selector kind describes what happened to the snippet.  The values are:\n
-help.set.format.when = The when-did-it-occur selector kind describes if this is a direct or indirect action.  The values are:\n
-help.set.format.resolve = The resolution-state selector kind describes the state of resolution/definition of the snippet.  The values are:\n
-help.set.format.unresolved = The unresolved-count selector kind describes the number of unresolved references.  The values are:\n
-help.set.format.errors = The errors-count selector kind describes the number of errors.  The values are:\n
-help.set.format.end = \n\
+matches if one of the values matches.\n\n\
+The case selector kind describes the kind of snippet.  The values are:\n\t\
+   import     -- import declaration\n\t\
+   class      -- class declaration\n\t\
+   interface  -- interface declaration\n\t\
+   enum       -- enum declaration\n\t\
+   annotation -- annotation interface declaration\n\t\
+   method     -- method declaration -- note: {type}==parameter-types\n\t\
+   vardecl    -- variable declaration without init\n\t\
+   varinit    -- variable declaration with init\n\t\
+   expression -- expression -- note: {name}==scratch-variable-name\n\t\
+   varvalue   -- variable value expression\n\t\
+   assignment -- assign variable\n\t\
+   statement  -- statement\n\
+The action selector kind describes what happened to the snippet.  The values are:\n\t\
+   added     -- snippet has been added\n\t\
+   modified  -- an existing snippet has been modified\n\t\
+   replaced  -- an existing snippet has been replaced with a new snippet\n\t\
+   overwrote -- an existing snippet has been overwritten\n\t\
+   dropped   -- snippet has been dropped\n\t\
+   used      -- snippet was used when it cannot be\n\
+The when-did-it-occur selector kind describes if this is a direct or indirect action.  The values are:\n\t\
+   primary -- the entered snippet\n\t\
+   update  -- an update to a dependent snippet\n\
+The resolution-state selector kind describes the state of resolution/definition of the snippet.  The values are:\n\t\
+   ok         -- resolved correctly\n\t\
+   defined    -- defined despite recoverably unresolved references\n\t\
+   notdefined -- not defined because of recoverably unresolved references\n\
+The unresolved-count selector kind describes the number of unresolved references.  The values are:\n\t\
+   unresolved0 -- no names are unresolved\n\t\
+   unresolved1 -- one name is unresolved\n\t\
+   unresolved2 -- two or more names are unresolved\n\
+The errors-count selector kind describes the number of errors.  The values are:\n\t\
+   error0 -- no errors\n\t\
+   error1 -- one error\n\t\
+   error2 -- two or more errors\n\n\
 Examples:\n\t\
 /set format myformat action 'Created' added-primary\n\t\
 /set format myformat action 'Update replaced' replaced-update\n\t\
@@ -73,7 +451,7 @@
 
 help.set.feedback = \
 Set the feedback mode describing displayed feedback for entered snippets and commands.\n\
-\n\
+\n\t\
 /set feedback <mode>\n\
 \n\
 Where <mode> is the name of a previously defined feedback mode.\n\
@@ -83,7 +461,7 @@
 
 help.set.newmode = \
 Create a user-defined feedback mode, optionally copying from an existing mode.\n\
-\n\
+\n\t\
 /set newmode <new-mode> [command|quiet [<old-mode>]]\n\
 \n\
 Where <new-mode> is the name of a mode you wish to create.\n\
@@ -96,15 +474,32 @@
 
 help.set.prompt = \
 Set the prompts.  Both the normal prompt and the continuation-prompt must be set.\n\
-\n\
-/set prompt <mode> \"<prompt>\" \"<continuation-propmt>\"\n\
+\n\t\
+/set prompt <mode> \"<prompt>\" \"<continuation-prompt>\"\n\
 \n\
 Where <mode> is the name of a previously defined feedback mode.\n\
-Where <prompt> and <continuation-propmt> are quoted strings printed as input prompts;\n\
+Where <prompt> and <continuation-prompt> are quoted strings printed as input prompts;\n\
 Both may optionally contain '%s' which will be substituted with the next snippet id --\n\
 note that what is entered may not be assigned that id, for example it may be an error or command.\n\
 The continuation-prompt is used on the second and subsequent lines of a multi-line snippet.\n
 
+help.set.editor =\
+Specify the command to launch for the /edit command.\n\
+\n\t\
+/set editor <command> <optional-arg>...\n\
+\n\
+The <command> is an operating system dependent string.\n\
+The <command> may include space-separated arguments (such as flags) -- <optional-arg>....\n\
+When /edit is used, the temporary file to edit will be appended as the last argument.
+
+help.set.start =\
+Set the start-up configuration -- a sequence of snippets and commands read at start-up.\n\
+\n\t\
+/set start <file>\n\
+\n\
+The contents of the specified <file> become the default start-up snippets and commands --\n\
+which are run when the jshell tool is started or reset.
+
 startup.feedback = \
 /set newmode normal command    \n\
 /set prompt normal '\\n-> ' '>> '    \n\
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Wed Jul 05 21:31:37 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Mon Apr 04 10:31:20 2016 -0700
@@ -651,17 +651,19 @@
             ModifierDiagnostic(List<Modifier> list, boolean fatal) {
                 this.fatal = fatal;
                 StringBuilder sb = new StringBuilder();
-                sb.append((list.size() > 1) ? "Modifiers " : "Modifier ");
                 for (Modifier mod : list) {
                     sb.append("'");
                     sb.append(mod.toString());
                     sb.append("' ");
                 }
-                sb.append("not permitted in top-level declarations");
-                if (!fatal) {
-                    sb.append(", ignored");
-                }
-                this.message = sb.toString();
+                String key = (list.size() > 1)
+                        ? fatal
+                            ? "jshell.diag.modifier.plural.fatal"
+                            : "jshell.diag.modifier.plural.ignore"
+                        : fatal
+                            ? "jshell.diag.modifier.single.fatal"
+                            : "jshell.diag.modifier.single.ignore";
+                this.message = state.messageFormat(key, sb.toString());
             }
 
             @Override
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java	Wed Jul 05 21:31:37 2017 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java	Mon Apr 04 10:31:20 2016 -0700
@@ -29,12 +29,14 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintStream;
-import java.util.ArrayList;
+import java.text.MessageFormat;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.MissingResourceException;
 import java.util.Objects;
+import java.util.ResourceBundle;
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
 
@@ -42,7 +44,6 @@
 import jdk.internal.jshell.debug.InternalDebugControl;
 import static java.util.stream.Collectors.collectingAndThen;
 import static java.util.stream.Collectors.toList;
-import static jdk.internal.jshell.debug.InternalDebugControl.DBG_EVNT;
 import static jdk.jshell.Util.expunge;
 import jdk.jshell.Snippet.Status;
 
@@ -91,10 +92,11 @@
     private final Map<Subscription, Consumer<SnippetEvent>> keyStatusListeners = new HashMap<>();
     private boolean closed = false;
 
-
     private ExecutionControl executionControl = null;
     private SourceCodeAnalysisImpl sourceCodeAnalysis = null;
 
+    private static final String L10N_RB_NAME    = "jdk.jshell.resources.l10n";
+    private static ResourceBundle outputRB  = null;
 
     JShell(Builder b) {
         this.in = b.in;
@@ -558,8 +560,8 @@
         checkIfAlive();
         checkValidSnippet(snippet);
         if (snippet.status() != Status.VALID) {
-            throw new IllegalArgumentException("Snippet parameter of varValue() '" +
-                    snippet + "' must be VALID, it is: " + snippet.status());
+            throw new IllegalArgumentException(
+                    messageFormat("jshell.exc.var.not.valid",  snippet, snippet.status()));
         }
         String value = executionControl().commandVarValue(maps.classFullName(snippet), snippet.name());
         return expunge(value);
@@ -680,7 +682,7 @@
      */
     private void checkIfAlive()  throws IllegalStateException {
         if (closed) {
-            throw new IllegalStateException("JShell (" + this + ") has been closed.");
+            throw new IllegalStateException(messageFormat("jshell.exc.closed", this));
         }
     }
 
@@ -693,13 +695,36 @@
      */
     private Snippet checkValidSnippet(Snippet sn) {
         if (sn == null) {
-            throw new NullPointerException("Snippet must not be null");
+            throw new NullPointerException(messageFormat("jshell.exc.null"));
         } else {
             if (sn.key().state() != this) {
-                throw new IllegalArgumentException("Snippet not from this JShell");
+                throw new IllegalArgumentException(messageFormat("jshell.exc.alien"));
             }
             return sn;
         }
     }
 
+    /**
+     * Format using resource bundle look-up using MessageFormat
+     *
+     * @param key the resource key
+     * @param args
+     */
+    String messageFormat(String key, Object... args) {
+        if (outputRB == null) {
+            try {
+                outputRB = ResourceBundle.getBundle(L10N_RB_NAME);
+            } catch (MissingResourceException mre) {
+                throw new InternalError("Cannot find ResourceBundle: " + L10N_RB_NAME);
+            }
+        }
+        String s;
+        try {
+            s = outputRB.getString(key);
+        } catch (MissingResourceException mre) {
+            throw new InternalError("Missing resource: " + key + " in " + L10N_RB_NAME);
+        }
+        return MessageFormat.format(s, args);
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/resources/l10n.properties	Mon Apr 04 10:31:20 2016 -0700
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+jshell.diag.modifier.plural.fatal = Modifiers {0} not permitted in top-level declarations
+jshell.diag.modifier.plural.ignore = Modifiers {0} not permitted in top-level declarations, ignored
+jshell.diag.modifier.single.fatal = Modifier {0} not permitted in top-level declarations
+jshell.diag.modifier.single.ignore = Modifier {0} not permitted in top-level declarations, ignored
+
+jshell.exc.null = Snippet must not be null
+jshell.exc.alien = Snippet not from this JShell
+jshell.exc.closed = JShell ({0}) has been closed.
+jshell.exc.var.not.valid = Snippet parameter of varValue() {0} must be VALID, it is: {1}
--- a/langtools/test/jdk/jshell/ReplToolTesting.java	Wed Jul 05 21:31:37 2017 +0200
+++ b/langtools/test/jdk/jshell/ReplToolTesting.java	Mon Apr 04 10:31:20 2016 -0700
@@ -29,6 +29,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.function.Consumer;
 import java.util.function.Function;
@@ -194,10 +195,10 @@
     }
 
     public void test(boolean isDefaultStartUp, String[] args, ReplTest... tests) {
-        test(isDefaultStartUp, args, DEFAULT_STARTUP_MESSAGE, tests);
+        test(Locale.ROOT, isDefaultStartUp, args, DEFAULT_STARTUP_MESSAGE, tests);
     }
 
-    public void test(boolean isDefaultStartUp, String[] args, String startUpMessage, ReplTest... tests) {
+    public void test(Locale locale, boolean isDefaultStartUp, String[] args, String startUpMessage, ReplTest... tests) {
         this.isDefaultStartUp = isDefaultStartUp;
         initSnippets();
         ReplTest[] wtests = new ReplTest[tests.length + 3];
@@ -206,7 +207,7 @@
         wtests[1] = a -> assertCommand(a, "/debug 0", null);
         System.arraycopy(tests, 0, wtests, 2, tests.length);
         wtests[tests.length + 2] = a -> assertCommand(a, "/exit", null);
-        testRaw(args, wtests);
+        testRaw(locale, args, wtests);
     }
 
     private void initSnippets() {
@@ -230,7 +231,7 @@
         prefs = new MemoryPreferences();
     }
 
-    public void testRaw(String[] args, ReplTest... tests) {
+    public void testRaw(Locale locale, String[] args, ReplTest... tests) {
         cmdin = new WaitingTestingInputStream();
         cmdout = new ByteArrayOutputStream();
         cmderr = new ByteArrayOutputStream();
@@ -246,7 +247,8 @@
                 userin,
                 new PrintStream(userout),
                 new PrintStream(usererr),
-                prefs);
+                prefs,
+                locale);
         repl.testPrompt = true;
         try {
             repl.start(args);
@@ -258,7 +260,7 @@
         String ceos = getCommandErrorOutput();
         String uos = getUserOutput();
         String ueos = getUserErrorOutput();
-        assertTrue((cos.isEmpty() || cos.startsWith("|  Goodbye")),
+        assertTrue((cos.isEmpty() || cos.startsWith("|  Goodbye") || !locale.equals(Locale.ROOT)),
                 "Expected a goodbye, but got: " + cos);
         assertTrue(ceos.isEmpty(), "Expected empty error output, got: " + ceos);
         assertTrue(uos.isEmpty(), "Expected empty output, got: " + uos);
@@ -459,7 +461,7 @@
 
     private List<String> computeCompletions(String code, boolean isSmart) {
         JShellTool js = this.repl != null ? this.repl
-                                      : new JShellTool(null, null, null, null, null, null, null, prefs);
+                                      : new JShellTool(null, null, null, null, null, null, null, prefs, Locale.ROOT);
         int cursor =  code.indexOf('|');
         code = code.replace("|", "");
         assertTrue(cursor > -1, "'|' not found: " + code);
--- a/langtools/test/jdk/jshell/StartOptionTest.java	Wed Jul 05 21:31:37 2017 +0200
+++ b/langtools/test/jdk/jshell/StartOptionTest.java	Mon Apr 04 10:31:20 2016 -0700
@@ -37,6 +37,7 @@
 import java.io.PrintStream;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Path;
+import java.util.Locale;
 import java.util.function.Consumer;
 
 import jdk.internal.jshell.tool.JShellTool;
@@ -55,7 +56,8 @@
 
     private JShellTool getShellTool() {
         return new JShellTool(null, new PrintStream(out), new PrintStream(err), null, null, null,
-                              null, new ReplToolTesting.MemoryPreferences());
+                              null, new ReplToolTesting.MemoryPreferences(),
+                              Locale.ROOT);
     }
 
     private String getOutput() {
@@ -116,10 +118,10 @@
         Compiler compiler = new Compiler();
         Path p = compiler.getPath("file.txt");
         compiler.writeToFile(p);
-        start("", "Argument to -startup missing.\n", "-startup");
+        start("", "'-startup' requires a filename argument.\n", "-startup");
         start("", "Conflicting -startup or -nostartup option.\n", "-startup", p.toString(), "-startup", p.toString());
         start("", "Conflicting -startup or -nostartup option.\n", "-nostartup", "-startup", p.toString());
-        start("", "Conflicting -startup option.\n", "-startup", p.toString(), "-nostartup");
+        start("", "Conflicting -startup or -nostartup option.\n", "-startup", p.toString(), "-nostartup");
     }
 
     @Test
--- a/langtools/test/jdk/jshell/ToolBasicTest.java	Wed Jul 05 21:31:37 2017 +0200
+++ b/langtools/test/jdk/jshell/ToolBasicTest.java	Mon Apr 04 10:31:20 2016 -0700
@@ -43,6 +43,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Locale;
 import java.util.Scanner;
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
@@ -463,7 +464,7 @@
                     (a) -> assertCommandCheckOutput(a, "printf(\"\")", assertStartsWith("|  Error:\n|  cannot find symbol"))
             );
             test((a) -> assertCommand(a, "printf(\"A\")", "", "", null, "A", ""));
-            test(false, new String[]{"-startup", "UNKNOWN"}, "|  File 'UNKNOWN' for start-up is not found.");
+            test(Locale.ROOT, false, new String[]{"-startup", "UNKNOWN"}, "|  File 'UNKNOWN' for start-up is not found.");
         } finally {
             removeStartup();
         }
@@ -478,9 +479,9 @@
                 (a) -> assertCommand(a, "a", "|  Variable a of type double has value 10.0\n")
         );
         Path unknown = compiler.getPath("UNKNOWN.jar");
-        test(true, new String[]{unknown.toString()},
-                "|  File '" + unknown
-                + "' is not found: " + unresolvableMessage(unknown) + "\n");
+        test(Locale.ROOT, true, new String[]{unknown.toString()},
+                "|  File " + unknown
+                + " is not found: " + unresolvableMessage(unknown) + "\n");
     }
 
     public void testReset() {
--- a/langtools/test/jdk/jshell/ToolFormatTest.java	Wed Jul 05 21:31:37 2017 +0200
+++ b/langtools/test/jdk/jshell/ToolFormatTest.java	Mon Apr 04 10:31:20 2016 -0700
@@ -62,7 +62,7 @@
                     (a) -> assertCommand(a, "/set format test result '={value} ' expression", ""),
                     (a) -> assertCommand(a, "/set format test display '{pre}{action}{ftype}{fname}{result}{resolve}'", ""),
                     (a) -> assertCommand(a, "/set format test display '{pre}HI this is enum' enum", ""),
-                    (a) -> assertCommand(a, "/set feedback test", "$ Feedback mode: test"),
+                    (a) -> assertCommandOutputStartsWith(a, "/set feedback test", "$ Feedback mode: test"),
                     (a) -> assertCommand(a, "class D {}", "$ ADD :D OK"),
                     (a) -> assertCommand(a, "void m() {}", "$ ADD []:m OK"),
                     (a) -> assertCommand(a, "interface EX extends EEX {}", "$ ADD :EX NODEF"),
@@ -184,18 +184,18 @@
                     (a) -> assertCommandOutputStartsWith(a, "/set newmode te2",
                             "|  Created new feedback mode: te2"),
                     (a) -> assertCommandOutputStartsWith(a, "/set newmode te2 command",
-                            "|  Expected a new feedback mode name. te2 is a known feedback mode"),
+                            "|  Expected a new feedback mode name. 'te2' is a known feedback mode"),
                     (a) -> assertCommandOutputStartsWith(a, "/set newmode te command normal",
                             "|  Created new feedback mode: te"),
                     (a) -> assertCommand(a, "/set format te errorpre 'ERROR: '", ""),
                     (a) -> assertCommandOutputStartsWith(a, "/set feedback te",
                             ""),
                     (a) -> assertCommandOutputStartsWith(a, "/set ",
-                            "ERROR: The /set command requires arguments"),
+                            "ERROR: The '/set' command requires a sub-command and arguments"),
                     (a) -> assertCommandOutputStartsWith(a, "/set xyz",
-                            "ERROR: Not a valid argument to /set"),
+                            "ERROR: Invalid '/set' argument: xyz"),
                     (a) -> assertCommandOutputStartsWith(a, "/set f",
-                            "ERROR: Ambiguous argument to /set"),
+                            "ERROR: Ambiguous sub-command argument to '/set': f"),
                     (a) -> assertCommandOutputStartsWith(a, "/set feedback",
                             "ERROR: Expected a feedback mode"),
                     (a) -> assertCommandOutputStartsWith(a, "/set feedback xyz",
@@ -266,19 +266,4 @@
             });
         }
     }
-
-    public void testSetHelpError() {
-        try {
-            test(
-                    (a) -> assertCommandOutputStartsWith(a, "/set newmode te command normal", "|  Created new feedback mode: te"),
-                    (a) -> assertCommand(a, "/set format te errorpre 'ERROR: '", ""),
-                    (a) -> assertCommandOutputStartsWith(a, "/set feedback te", "|  Feedback mode: te"),
-                    (a) -> assertCommandOutputContains(a, "/help /set xyz", "ERROR: Not a valid argument to /set: xyz"),
-                    (a) -> assertCommandOutputContains(a, "/help /set f", "ERROR: Ambiguous argument to /set: f")
-            );
-        } finally {
-            assertCommandCheckOutput(false, "/set feedback normal", s -> {
-            });
-        }
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/ToolLocaleMessageTest.java	Mon Apr 04 10:31:20 2016 -0700
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8147515
+ * @summary Tests for output customization
+ * @library /tools/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.jdeps/com.sun.tools.javap
+ *          jdk.jshell/jdk.internal.jshell.tool
+ * @build KullaTesting TestingInputStream toolbox.ToolBox Compiler
+ * @run testng ToolLocaleMessageTest
+ */
+
+import java.util.Locale;
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+@Test
+public class ToolLocaleMessageTest extends ReplToolTesting {
+
+    void testLocale(ReplTest... tests) {
+        test(Locale.getDefault(), false, new String[]{"-nostartup"}, "", tests);
+    }
+
+    void assertCommandOK(boolean after, String cmd, String... contains) {
+        assertCommandCheckOutput(after, cmd, s -> {
+            assertFalse(s.contains("Exception"), "Output of '" + cmd + "' has Exception: " + s);
+            assertFalse(s.contains("ERROR:"), "Output of '" + cmd + "' has error: " + s);
+            for (String m : contains) {
+                assertTrue(s.contains(m), "Expected to find '" + m + "' in output of '" + cmd + "' -- output: " + s);
+            }
+        });
+    }
+
+    void assertCommandFail(boolean after, String cmd, String... contains) {
+        assertCommandCheckOutput(after, cmd, s -> {
+            assertFalse(s.contains("Exception"), "Output of '" + cmd + "' has Exception: " + s);
+            assertTrue(s.contains("ERROR:"), "Expected to find error in output of '" + cmd + "' has error: " + s);
+            for (String m : contains) {
+                assertTrue(s.contains(m), "Expected to find '" + m + "' in output of '" + cmd + "' -- output: " + s);
+            }
+        });
+    }
+
+    public void testTerminate() {
+        testLocale(
+                (a) -> assertCommandOK(a, "System.exit(1)", "/reload")
+        );
+    }
+
+    public void testSample() {
+        try {
+            testLocale(
+                    (a) -> assertCommandOK(a, "/set newmode test command normal", "test"),
+                    (a) -> assertCommandOK(a, "/set format test errorpre 'ERROR: '"),
+                    (a) -> assertCommandOK(a, "/set feedback test", "test"),
+
+                    (a) -> assertCommandFail(a, "/turkey", "/turkey"),
+                    (a) -> assertCommandFail(a, "/s", "/set"),
+                    (a) -> assertCommandOK(a, "void m() { blah(); }", "blah"),
+                    (a) -> assertCommandOK(a, "void m() {}"),
+                    (a) -> assertCommandOK(a, "class C {}"),
+                    (a) -> assertCommandOK(a, "47"),
+                    (a) -> assertCommandOK(a, "double d"),
+                    (a) -> assertCommandOK(a, "/drop m", "m"),
+                    (a) -> assertCommandOK(a, "void dup() {}"),
+                    (a) -> assertCommandOK(a, "int dup"),
+
+                    (a) -> assertCommandOK(a, "/set feedback normal", "normal")
+            );
+        } finally {
+            assertCommandOK(false, "/set feedback normal");
+        }
+    }
+
+    public void testCommand() {
+        try {
+            testLocale(
+                    (a) -> assertCommandOK(a, "/set newmode test command normal", "test"),
+                    (a) -> assertCommandOK(a, "/set format test errorpre 'ERROR: '"),
+                    (a) -> assertCommandOK(a, "/set feedback test", "test"),
+
+                    (a) -> assertCommandFail(a, "/list zebra"),
+                    (a) -> assertCommandFail(a, "/set editor", "/set editor"),
+                    (a) -> assertCommandFail(a, "/set snowball", "/set", "snowball"),
+                    (a) -> assertCommandFail(a, "/set", "/set", "/help"),
+                    (a) -> assertCommandFail(a, "/set f", "feedback"),
+                    (a) -> assertCommandFail(a, "/classpath", "/classpath"),
+                    (a) -> assertCommandFail(a, "/help rabbits", "rabbits"),
+                    (a) -> assertCommandFail(a, "/drop"),
+                    (a) -> assertCommandFail(a, "/drop rats"),
+                    (a) -> assertCommandOK(a, "void dup() {}"),
+                    (a) -> assertCommandOK(a, "int dup"),
+                    (a) -> assertCommandFail(a, "/drop dup"),
+                    (a) -> assertCommandFail(a, "/edit zebra", "zebra"),
+                    (a) -> assertCommandFail(a, "/list zebra", "zebra", "/list"),
+                    (a) -> assertCommandFail(a, "/open", "/open"),
+                    (a) -> assertCommandFail(a, "/open zebra", "zebra", "/open"),
+                    (a) -> assertCommandFail(a, "/reload zebra", "zebra", "/reload"),
+                    (a) -> assertCommandFail(a, "/save", "/save"),
+                    (a) -> assertCommandFail(a, "/-99"),
+
+                    (a) -> assertCommandOK(a, "/set feedback normal", "normal")
+            );
+        } finally {
+            assertCommandOK(false, "/set feedback normal");
+        }
+    }
+
+    public void testHelp() {
+        testLocale(
+                (a) -> assertCommandOK(a, "/help", "/list", "/save", "/set", "[restore]"),
+                (a) -> assertCommandOK(a, "/help /list", "start", "all"),
+                (a) -> assertCommandOK(a, "/help /edit", "/set editor"),
+                (a) -> assertCommandOK(a, "/help /drop", "/drop"),
+                (a) -> assertCommandOK(a, "/help /save", "all", "start"),
+                (a) -> assertCommandOK(a, "/help /open", "/open"),
+                (a) -> assertCommandOK(a, "/help /reload", "restore"),
+                (a) -> assertCommandOK(a, "/help /help", "intro"),
+                (a) -> assertCommandOK(a, "/help /set", "newmode"),
+                (a) -> assertCommandOK(a, "/help /?", "intro"),
+                (a) -> assertCommandOK(a, "/help intro", "/help"),
+                (a) -> assertCommandOK(a, "/help /set format", "import", "case", "{value}", "added"),
+                (a) -> assertCommandOK(a, "/help /set feedback", "newmode"),
+                (a) -> assertCommandOK(a, "/help /set newmode", "feedback"),
+                (a) -> assertCommandOK(a, "/help /set prompt", "/set prompt"),
+                (a) -> assertCommandOK(a, "/help /set editor", "/edit")
+        );
+    }
+
+    public void testFeedbackError() {
+        try {
+            testLocale(
+                    (a) -> assertCommandOK(a, "/set newmode tee command foo", "foo"),
+                    (a) -> assertCommandOK(a, "/set newmode tee flurb", "command", "quiet"),
+                    (a) -> assertCommandOK(a, "/set newmode te2", "te2"),
+                    (a) -> assertCommandOK(a, "/set newmode te2 command", "te2"),
+                    (a) -> assertCommandOK(a, "/set newmode te command normal", "te"),
+                    (a) -> assertCommandOK(a, "/set format te errorpre 'ERROR: '"),
+                    (a) -> assertCommandOK(a, "/set feedback te"),
+
+                    (a) -> assertCommandFail(a, "/set "),
+                    (a) -> assertCommandFail(a, "/set xyz", "xyz"),
+                    (a) -> assertCommandFail(a, "/set f", "/set", "f"),
+                    (a) -> assertCommandFail(a, "/set feedback"),
+                    (a) -> assertCommandFail(a, "/set feedback xyz"),
+                    (a) -> assertCommandFail(a, "/set format"),
+                    (a) -> assertCommandFail(a, "/set format xyz"),
+                    (a) -> assertCommandFail(a, "/set format t"),
+                    (a) -> assertCommandFail(a, "/set format te"),
+                    (a) -> assertCommandFail(a, "/set format te fld"),
+                    (a) -> assertCommandFail(a, "/set format te fld aaa", "aaa"),
+                    (a) -> assertCommandFail(a, "/set format te fld 'aaa' frog"),
+                    (a) -> assertCommandFail(a, "/set format te fld 'aaa' import-frog"),
+                    (a) -> assertCommandFail(a, "/set format te fld 'aaa' import-import"),
+                    (a) -> assertCommandFail(a, "/set format te fld 'aaa' import,added"),
+                    (a) -> assertCommandFail(a, "/set newmode"),
+                    (a) -> assertCommandFail(a, "/set newmode te"),
+                    (a) -> assertCommandFail(a, "/set newmode x xyz"),
+                    (a) -> assertCommandFail(a, "/set newmode x quiet y"),
+                    (a) -> assertCommandFail(a, "/set prompt"),
+                    (a) -> assertCommandFail(a, "/set prompt te"),
+                    (a) -> assertCommandFail(a, "/set prompt te aaa xyz", "aaa"),
+                    (a) -> assertCommandFail(a, "/set prompt te 'aaa' xyz", "xyz"),
+                    (a) -> assertCommandFail(a, "/set prompt"),
+                    (a) -> assertCommandFail(a, "/set prompt te"),
+                    (a) -> assertCommandFail(a, "/set prompt te aaa"),
+                    (a) -> assertCommandFail(a, "/set prompt te 'aaa'"),
+
+                    (a) -> assertCommandOK(a, "/set feedback normal")
+            );
+        } finally {
+            assertCommandOK(false, "/set feedback normal");
+        }
+    }
+
+
+}
--- a/langtools/test/jdk/jshell/ToolReloadTest.java	Wed Jul 05 21:31:37 2017 +0200
+++ b/langtools/test/jdk/jshell/ToolReloadTest.java	Mon Apr 04 10:31:20 2016 -0700
@@ -71,7 +71,7 @@
         Path classpath = compiler.getPath(outDir);
         test(
                 (a) -> assertCommand(a, "/classpath " + classpath,
-                        String.format("|  Path %s added to classpath\n", classpath)),
+                        String.format("|  Path '%s' added to classpath\n", classpath)),
                 (a) -> assertMethod(a, "String foo() { return (new pkg.A()).toString(); }",
                         "()String", "foo"),
                 (a) -> assertVariable(a, "String", "v", "foo()", "\"A\""),