From 3b20e2c7de0ebe8aa4bf8b1490b2df6168bfbae3 Mon Sep 17 00:00:00 2001 From: Andreas Deininger Date: Thu, 4 Mar 2021 11:12:33 +0100 Subject: [PATCH] Manual: adding chapter 19.6 Controlling the locale (#1326) --- docs/index.adoc | 125 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/docs/index.adoc b/docs/index.adoc index b9d83bd58..3fde1b7ff 100644 --- a/docs/index.adoc +++ b/docs/index.adoc @@ -49,7 +49,7 @@ Picocli is a one-file framework for creating Java command line applications with It supports a variety of command line syntax styles including POSIX, GNU, MS-DOS and more. It generates highly customizable usage help messages that use <> to contrast important elements and reduce the cognitive load on the user. Picocli-based applications can have link:autocomplete.html[command line TAB completion] showing available options, option parameters and subcommands, for any level of nested subcommands. -Picocli-based applications can be ahead-of-time compiled to a image:https://www.graalvm.org/resources/img/logo-colored.svg[GraalVM] +Picocli-based applications can be ahead-of-time compiled to an image:https://www.graalvm.org/resources/img/logo-colored.svg[GraalVM] <>, with extremely fast startup time and lower memory requirements, which can be distributed as a single executable file. Picocli <> for your application (HTML, PDF and Unix man pages). @@ -9573,6 +9573,129 @@ Options with a <> can use the `${DEFAULT-VALUE}` v userName=Specify the user name. The default is ${DEFAULT-VALUE}. ---- +=== Controlling the locale + +In your localized application, it may be desirable to specify the locale in order to determine the language of message texts and help output. One way of controlling the locale is to give `-Duser.language=de` as VM argument when running the app. A more accessible and user-friendly approach is to to implement a command line parameter (e. g. `--locale`) inside your app which can be used to change the locale. The latter technique requires a two-phase approach to parsing in your application in order to get a valid load order. The minimal example below demonstrates how to implement this two phase approach: + +.Java +[source,java,role="primary"] +---- +class InitLocale { + @Option(names = { "-l", "--locale" }, description = "locale for message texts (phase 1)") + void setLocale(String locale) { + Locale.setDefault(new Locale(locale)); + } + + @Unmatched + List remainder; // ignore any other parameters and options in the first parsing phase +} + +@Command(name = "GreetingApp", resourceBundle = "mybundle", mixinStandardHelpOptions = true) +public class GreetingApp implements Runnable { + @Option(names = { "-l", "--locale" }, paramLabel = "") + private String ignored; + + @Parameters(arity = "1..", paramLabel = " ") + private String[] names; + + ResourceBundle bundle = ResourceBundle.getBundle("mybundle"); + + public void run() { // business logic here + for (String name : names) { + System.out.println(MessageFormat.format(bundle.getString("Hello"), name)); + } + } + + public static void main(String[] args) { + // first phase: configure locale + new CommandLine(new InitLocale()).parseArgs(args); + + // second phase: parse all args (ignoring --locale) and run the app + new CommandLine(new GreetingApp()).execute(args); + } +} +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +class InitLocale { + @Option(names = ["-l", "--locale"], description = ["locale for message texts (phase 1)"]) + fun setLocale(locale: String?) { + Locale.setDefault(Locale(locale)) + } + + @Unmatched + lateinit var others : List // ignore other parameters/options in first parsing phase +} + +@Command(name = "GreetingApp", resourceBundle = "mybundle", mixinStandardHelpOptions = true) +class GreetingApp : Runnable { + @Option(names = ["-l", "--locale"], paramLabel = "") + lateinit var ignored: String + + @Parameters(arity = "1..", paramLabel = " ") + lateinit var names: Array + + private var bundle = ResourceBundle.getBundle("mybundle") + + override fun run() { // business logic here + names.onEach { + println(MessageFormat.format(bundle.getString("Hello"), it)) + } + } +} + +fun main(args: Array) { + // first phase: configure locale + CommandLine(picocli.examples.kotlin.i18n.localecontrol.InitLocale()).parseArgs(*args) + + // second phase: parse all args (ignoring --locale) and run the app + exitProcess(CommandLine(GreetingApp()).execute(*args)) +} +---- + +Now put the default properties file (`mybundle.properties`, in English) and the Spanish language variant (`mybundle_es.properties`) in place: + +.mybundle.properties +---- +Hello = Hello {0}! +---- + +.mybundle_es.properties +---- +Hello = Hola {0}! +---- + +Eventually, we are ready to run our application: + +[source,bash] +---- +java -cp "picocli-4.6.2-SNAPSHOT.jar;myapp.jar" org.myorg.GreetingApp Sarah Lea +---- + +With no command line parameter `--locale` given, the message texts are printed in the default language (here: English): + +---- +Hello Sarah! +Hello Lea! +---- + +In order to control the locale choosen for our output, we have to make use of the command line parameter `--locale`: + +[source,bash] +---- +java -cp "picocli-4.6.2-SNAPSHOT.jar;myapp.jar" org.myorg.GreetingApp --locale=es Sarah Lea +---- + +Now our message texts are printed in Spanish: + +---- +Hola Sarah! +Hola Lea! +---- + +Using the command line parameter `--locale`, one can also determine the language of the help output of your application. The https://github.com/remkop/picocli/blob/master/picocli-examples[`picocli-examples`] module has examples with fully implemented, localized help output, coded both in https://github.com/remkop/picocli/blob/master/picocli-examples/src/main/java/picocli/examples/i18n/localecontrol/LocaleControl.java[Java] and https://github.com/remkop/picocli/tree/master/picocli-examples/src/main/kotlin/picocli/examples/kotlin/i18n/localecontrol/LocaleControl.kt[Kotlin]. == Variable Interpolation