{"payload":{"allShortcutsEnabled":false,"fileTree":{"src/main/java/sirius/kernel/nls":{"items":[{"name":"Babelfish.java","path":"src/main/java/sirius/kernel/nls/Babelfish.java","contentType":"file"},{"name":"Formatter.java","path":"src/main/java/sirius/kernel/nls/Formatter.java","contentType":"file"},{"name":"NLS.java","path":"src/main/java/sirius/kernel/nls/NLS.java","contentType":"file"},{"name":"NonCachingUTF8Control.java","path":"src/main/java/sirius/kernel/nls/NonCachingUTF8Control.java","contentType":"file"},{"name":"README.md","path":"src/main/java/sirius/kernel/nls/README.md","contentType":"file"},{"name":"Translation.java","path":"src/main/java/sirius/kernel/nls/Translation.java","contentType":"file"}],"totalCount":6},"src/main/java/sirius/kernel":{"items":[{"name":"async","path":"src/main/java/sirius/kernel/async","contentType":"directory"},{"name":"cache","path":"src/main/java/sirius/kernel/cache","contentType":"directory"},{"name":"commons","path":"src/main/java/sirius/kernel/commons","contentType":"directory"},{"name":"di","path":"src/main/java/sirius/kernel/di","contentType":"directory"},{"name":"health","path":"src/main/java/sirius/kernel/health","contentType":"directory"},{"name":"info","path":"src/main/java/sirius/kernel/info","contentType":"directory"},{"name":"nls","path":"src/main/java/sirius/kernel/nls","contentType":"directory"},{"name":"settings","path":"src/main/java/sirius/kernel/settings","contentType":"directory"},{"name":"timer","path":"src/main/java/sirius/kernel/timer","contentType":"directory"},{"name":"tokenizer","path":"src/main/java/sirius/kernel/tokenizer","contentType":"directory"},{"name":"xml","path":"src/main/java/sirius/kernel/xml","contentType":"directory"},{"name":"AutoSetup.java","path":"src/main/java/sirius/kernel/AutoSetup.java","contentType":"file"},{"name":"AutoSetupRule.java","path":"src/main/java/sirius/kernel/AutoSetupRule.java","contentType":"file"},{"name":"Classpath.java","path":"src/main/java/sirius/kernel/Classpath.java","contentType":"file"},{"name":"DockerHelper.java","path":"src/main/java/sirius/kernel/DockerHelper.java","contentType":"file"},{"name":"Killable.java","path":"src/main/java/sirius/kernel/Killable.java","contentType":"file"},{"name":"README.md","path":"src/main/java/sirius/kernel/README.md","contentType":"file"},{"name":"Setup.java","path":"src/main/java/sirius/kernel/Setup.java","contentType":"file"},{"name":"Sirius.java","path":"src/main/java/sirius/kernel/Sirius.java","contentType":"file"},{"name":"Startable.java","path":"src/main/java/sirius/kernel/Startable.java","contentType":"file"},{"name":"Stoppable.java","path":"src/main/java/sirius/kernel/Stoppable.java","contentType":"file"}],"totalCount":21},"src/main/java/sirius":{"items":[{"name":"kernel","path":"src/main/java/sirius/kernel","contentType":"directory"}],"totalCount":1},"src/main/java":{"items":[{"name":"sirius","path":"src/main/java/sirius","contentType":"directory"}],"totalCount":1},"src/main":{"items":[{"name":"java","path":"src/main/java","contentType":"directory"},{"name":"resources","path":"src/main/resources","contentType":"directory"}],"totalCount":2},"src":{"items":[{"name":"main","path":"src/main","contentType":"directory"},{"name":"test","path":"src/test","contentType":"directory"}],"totalCount":2},"":{"items":[{"name":".github","path":".github","contentType":"directory"},{"name":".run","path":".run","contentType":"directory"},{"name":"docs","path":"docs","contentType":"directory"},{"name":"src","path":"src","contentType":"directory"},{"name":".drone.yml","path":".drone.yml","contentType":"file"},{"name":".gitignore","path":".gitignore","contentType":"file"},{"name":"README.md","path":"README.md","contentType":"file"},{"name":"build.gradle.kts","path":"build.gradle.kts","contentType":"file"},{"name":"pom.xml","path":"pom.xml","contentType":"file"}],"totalCount":9}},"fileTreeProcessingTime":34.666841,"foldersToFetch":[],"repo":{"id":27138068,"defaultBranch":"develop","name":"sirius-kernel","ownerLogin":"scireum","currentUserCanPush":false,"isFork":false,"isEmpty":false,"createdAt":"2014-11-25T17:42:50.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/5050602?v=4","public":true,"private":false,"isOrgOwned":true},"symbolsExpanded":false,"treeExpanded":true,"refInfo":{"name":"master","listCacheKey":"v0:1708698242.0","canEdit":false,"refType":"branch","currentOid":"081e45779084c336e480bc1e2556ebf804211e29"},"path":"src/main/java/sirius/kernel/nls/Formatter.java","currentUser":null,"blob":{"rawLines":["/*"," * Made with all the love in the world"," * by scireum in Remshalden, Germany"," *"," * Copyright by scireum GmbH"," * http://www.scireum.de - info@scireum.de"," */","","package sirius.kernel.nls;","","import sirius.kernel.commons.Strings;","","import java.util.ArrayList;","import java.util.List;","import java.util.Map;","import java.util.Optional;","import java.util.TreeMap;","import java.util.function.Function;","","/**"," * An alternative for MessageFormat which generates strings by replacing named parameters in a given template."," *
"," * A formatter is created for a given template string which contains named parameters like {@code ${param1}}."," * Using one of the set methods, values for the parameters can be supplied. Calling {@code #format}"," * creates the output string."," *
"," * Non string objects which are passed in as parameters, will be converted using {@link NLS#toUserString(Object)}"," *
"," * A formatter is neither thread safe nor intended for reuse. Instead, a formatter is created, supplied with the"," * relevant parameters by chaining calls to set and then discarded after getting the result string via"," * format."," *
"," * An example call might look like this:"," *
"," * {@code"," * System.out.println("," * Formatter.create(\"Hello ${programmer}\")"," * .set(\"programmer\", \"Obi Wan\")"," * .format());"," * }"," *"," *
"," * {@link NLS} uses this class by supplied translated patterns when calling {@link NLS#fmtr(String)}."," *"," * @see NLS#fmtr(String)"," */","public class Formatter {"," private boolean urlEncode = false;"," private boolean jsEncode = false;"," private final Map "," * The given language will be used when converting non-string parameters."," *"," * @param pattern specifies the pattern to be used for creating the output"," * @param language specifies the language used when converting non-string parameters."," * @return this for fluently calling set methods."," */"," public static Formatter create(String pattern, String language) {"," Formatter result = new Formatter();"," result.pattern = pattern;"," result.language = language;"," return result;"," }",""," /**"," * Creates a new formatter with the given pattern."," * "," * Uses the currently active language when converting non-string parameters."," *"," * @param pattern specifies the pattern to be used for creating the output"," * @return this for fluently calling set methods."," */"," public static Formatter create(String pattern) {"," Formatter result = new Formatter();"," result.pattern = pattern;"," return result;"," }",""," /**"," * Creates a new formatter with auto url encoding turned on."," * "," * Any parameters passed to this formatter will be automatically url encoded."," *"," * @param pattern specifies the pattern to be used for creating the output"," * @return this for fluently calling set methods."," */"," public static Formatter createURLFormatter(String pattern) {"," Formatter result = new Formatter();"," result.pattern = pattern;"," result.urlEncode = true;"," return result;"," }",""," /**"," * Creates a new formatter with auto JavaScript encoding turned on."," * "," * Any parameters passed to this formatter will have its single and double quotes encoded."," *"," * @param pattern specifies the pattern to be used for creating the output"," * @return this for fluently calling set methods."," */"," public static Formatter createJSFormatter(String pattern) {"," Formatter result = new Formatter();"," result.pattern = pattern;"," result.jsEncode = true;"," return result;"," }",""," /**"," * Adds the replacement value to use for the given property."," *"," * @param property the parameter in the template string which should be replaced"," * @param value the value which should be used as replacement"," * @return this to permit fluent method chains"," */"," public Formatter set(String property, Object value) {"," if (value == null) {"," setDirect(property, \"\");"," } else if (value instanceof String string) {"," // We have to trim here to emulate the call to NLS.toUserString, but we can do this"," // here without having to resolve the current language..."," setDirect(property, string.trim());"," } else {"," setDirect(property, NLS.toUserString(value, fetchLanguage()));"," }",""," return this;"," }",""," private String fetchLanguage() {"," if (language == null) {"," language = NLS.getCurrentLanguage();"," }",""," return language;"," }",""," /**"," * Adds the replacement value to use for the given property, without url encoding the value."," * "," * Formatters created by #createURLFormatter perform automatic url conversion for all parameters."," * Using this method however, disables url encoding for the given parameter and value."," *"," * @param property the parameter in the template string which should be replaced"," * @param value the value which should be used as replacement"," * @return this to permit fluent method chains"," */"," public Formatter setUnencoded(String property, Object value) {"," if (value == null) {"," setDirectUnencoded(property, \"\");"," } else if (value instanceof String string) {"," // We have to trim here to emulate the call to NLS.toUserString, but we can do this"," // here without having to resolve the current language..."," setDirectUnencoded(property, string.trim());"," } else {"," setDirectUnencoded(property, NLS.toUserString(value, fetchLanguage()));"," }",""," return this;"," }",""," /**"," * Sets the whole context as parameters in this formatter."," * "," * Calls #set for each entry in the given map."," *"," * @param ctx a Map which provides a set of entries to replace."," * @return this to permit fluent method chains"," */"," public Formatter set(Map "," * Calls #setDirect for each entry in the given map. Note that only"," * toString is invoked on the value, therefore all strings remain untrimmed."," *"," * @param ctx a Map which provides a set of entries to replace."," * @return this to permit fluent method chains"," */"," public Formatter setDirect(Map "," * Sets the given string as replacement value for the named parameter. The value will not be sent through"," * {@link NLS#toUserString(Object)} and therefore not trimmed etc."," *"," * @param property the parameter in the template string which should be replaced"," * @param value the value which should be used as replacement"," * @return this to permit fluent method chains"," */"," public Formatter setDirect(String property, String value) {"," if (jsEncode) {"," replacement.put(property, escapeJS(value));"," return this;"," }",""," if (urlEncode) {"," replacement.put(property, Strings.urlEncode(value));"," return this;"," }",""," replacement.put(property, value);"," return this;"," }",""," /**"," * Directly sets the given string value for the given property without performing any URL encoding."," * "," * Sets the given string as replacement value for the named parameter. The value will not be sent through"," * {@link NLS#toUserString(Object)} and therefore not trimmed etc."," * "," * Note that this will not perform any URL encoding, even if {@link #createURLFormatter(String)} was used to"," * create this formatter."," *"," * @param property the parameter in the template string which should be replaced"," * @param value the value which should be used as replacement"," * @return this to permit fluent method chains"," */"," public Formatter setDirectUnencoded(String property, String value) {"," replacement.put(property, value);"," return this;"," }",""," /**"," * Adds a provider which can supply the formatter with parameter values."," * "," * As long as a non-empty Optional is used, the returned value will be used. Otherwise, the value provided"," * via one of the set methods is used."," *"," * @param parameterProvider the provider used to determine the value for a given parameter"," * @return this to permit fluent method chains"," */"," public Formatter withParameterProvider(Function "," * By default, an exception is thrown when a completely unknown parameter is being referenced. By calling this method"," * the parameter is simply assumed to be empty (\"\")."," *"," * @return this to permit fluent method chains"," */"," public Formatter ignoreMissingParameters() {"," this.ignoreMissingParameters = true;"," return this;"," }",""," /**"," * Generates the formatted string."," * "," * Applies all supplied replacement values on detected parameters formatted like {@code ${param}}."," *"," * @return the template string with all parameters replaced for which a value was supplied."," * @throws java.lang.IllegalArgumentException if the pattern is malformed"," */"," public String format() {"," return format(false);"," }",""," /**"," * Generates the formatted string using smart output formatting."," * "," * Applies all supplied replacement values on detected parameters formatted like {@code ${param}}."," * Block can be formed using '[' and ']' a whole block is only output, if at least one replacement"," * was not empty."," * "," * Consider the pattern {@code [${salutation} ][${firstname}] ${lastname}}. This will create"," * Mr. Foo Bar if all three parameters are filled, but Mr. Bar if the first name is missing"," * or Foo Bar if the salutation is missing."," *"," * @return the template string with all parameters replaced for which a value was supplied."," * @throws java.lang.IllegalArgumentException if the pattern is malformed"," */"," public String smartFormat() {"," return format(true);"," }",""," /*"," * Keeps track of the current smart formatting block being parsed."," */"," private static class Block {"," StringBuilder output = new StringBuilder();"," boolean replacementFound = false;"," int startIndex;"," }",""," /*"," * Stack based implementation parsing parameterized strings with smart blocks. Each nested block will"," * result in one stack level."," */"," private String format(boolean smart) {"," List