Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there any possibility to localize error messages? #1946

Open
lukaseckert opened this issue Feb 2, 2023 · 3 comments
Open

Is there any possibility to localize error messages? #1946

lukaseckert opened this issue Feb 2, 2023 · 3 comments
Labels
status: help-wanted 🆘 theme: usagehelp An issue or change related to the usage help message type: enhancement ✨
Milestone

Comments

@lukaseckert
Copy link

Hi,
first, thanks for this great piece of software! Currently I'm trying to localize the most common messages which a user might see when using a picocli-based app. Via the resource bundle, it was easy to translate options, usage help, etc. 👍 However this doesn't work for error/help messages, resulting in a mix of English and German in the output:

Unknown option: '--help'
Aufruf: my-cli-ap ...
Hier kommt eine Beschreibung auf Deutsch.
Optionen:
-n, --node=

I see that "Unknown option:" is hard-coded in CommandLine.UnmatchedArgumentException.describe() (line 18669), and requires some special handling for the plural, which cannot be solved by simple resource files. Then I checked if it would be possible so subclass the Interpreter to override describe(). This is obviously not a good idea as describe() does more than only building the string, and is also impossible as there is not setter for an extended Interpreter implementation.

I wondered if there are any plans to offer an extension point where a custom "MessageProvider" may be set. This interface could then have methods like buildUnknownOptionMessage(String optionName, boolean isPlural) and be implemented for most languages.
The same applies for many more methods, e.g. readUserInput() ("Enter value for %s: ")

@remkop
Copy link
Owner

remkop commented Feb 2, 2023

Indeed, this has been on the todo list for a long time.
See #485.

Some error messages are dynamically constructed but it should be possible to capture all patterns in MessageFormat.

It'll be some work though and my time to spend on picocli is extremely limited.

I'd be happy to review pull requests if anyone is interested in working on this.

@lukaseckert will you be able to provide a pull request?

@lukaseckert
Copy link
Author

Hi @remkop ,
I can give it a try, however this may take some time as I'm doing my first steps with picocli and also do have to work on it in my spare time ;)
I'm not sure what you mean by "should be possible to capture all patterns in MessageFormat".

@remkop
Copy link
Owner

remkop commented Feb 3, 2023

I'm not sure what you mean by "should be possible to capture all patterns in MessageFormat".

For example, there is some of the current picocli code, showing a method that dynamically creates an error message:

// current picocli code:
private static String createMissingParameterMessage(ArgSpec argSpec, Range arity, List<PositionalParamSpec> missingList, Stack<String> args, int available) {
    if (arity.min == 1) {
        if (argSpec.isOption()) {
            return "Missing required parameter for " + optionDescription("", argSpec, 0);
        }
        String sep = "";
        String names = ": ";
        String indices = "";
        String infix = " at index ";
        int count = 0;
        for (PositionalParamSpec missing : missingList) {
            if (missing.arity().min > 0) {
                names += sep + "'" + missing.paramLabel() + "'";
                indices += sep + missing.index();
                sep = ", ";
                count++;
            }
        }
        String msg = "Missing required parameter";
        if (count > 1 || arity.min - available > 1) {
            msg += "s";
        }
        if (count > 1) { infix = " at indices "; }
        return System.getProperty("picocli.verbose.errors") != null ? msg + names + infix + indices : msg + names;

    } else if (args.isEmpty()) {
        return optionDescription("", argSpec, 0) +
                " requires at least " + arity.min + " values, but none were specified.";
    } else {
        return optionDescription("", argSpec, 0) +
                " requires at least " + arity.min + " values, but only " + available + " were specified: " + reverse(args);
    }
}

In the resource bundle, we would have to have key-value pairs for all possible permutations that could result from this.
The values would all be in MessageFormat:

missingParam1=Missing required parameter for {0}
missingParamMulti1=Missing required parameter {0} at index {1,number}
missingParamMulti=Missing required parameters {0} at indices {1}
missingParamMulti1Short=Missing required parameter {0}
missingParamMultiShort=Missing required parameters {0}
requiredAllMissing={0} requires at least {1,number} values, but none were specified.
requiredSomeMissing={0} requires at least {1,number} values, but only {2,number} were specified: {3}

Then, the logic in that method would have the same conditionals, but, instead of constructing the English message, it would select the correct key, get the pattern from the resource bundle, and then format the result, something like this:

// future picocli code for createMissingParameterMessage
private static String createMissingParameterMessage(ArgSpec argSpec, Range arity, List<PositionalParamSpec> missingList, Stack<String> args, int available) {
...
    } else if (args.isEmpty()) {
        return MessageFormat.format(bundle.getString("requiredAllMissing"), 
                optionDescription("", argSpec, 0), arity.min);
    } else {
        return MessageFormat.format(bundle.getString("requiredSomeMissing"), 
                optionDescription("", argSpec, 0), arity.min, available, reverse(args));
    }
}

I can give it a try, however this may take some time as I'm doing my first steps with picocli and also do have to work on it in my spare time ;)

Sure, any help is welcome. Picocli is entirely done in my spare time also, so I fully understand! 😅

@remkop remkop added type: enhancement ✨ theme: usagehelp An issue or change related to the usage help message labels Feb 3, 2023
@remkop remkop added this to the 4.8 milestone Feb 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: help-wanted 🆘 theme: usagehelp An issue or change related to the usage help message type: enhancement ✨
Projects
None yet
Development

No branches or pull requests

2 participants