how to use #StringDef in an app with i18n - java

#StringDef is great for replacing Enum.
#StringDef(Standard, Mini)
public #interface Type;
But what if my app needs to support english, french and chinese?
So the standard might be "Standard", "Norme", and "标准" in three different countries. In that case, the Standard and Mini may need the context to get the real value.
How could we still use #StringDef in an app with i18n.

There is no out-of-the-box solution.
The recommended way is to store localized string resources in different directories (res/values-XX/strings.xml, where XX is en, fr etc).
https://developer.android.com/guide/topics/resources/localization.html
In this approach you need to use string id to get the localized string. You can try the following:
Use ids of strings instead:
#IntDef({R.string.standard, R.string.mini})
Use some helper to match #StringDef's string to localized string resorce.
Use enums.

Related

How to use String.format(Locale, ...)?

I am new in Android development and I'm trying this code:
String hms = String.format("%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(milliSeconds),
TimeUnit.MILLISECONDS.toMinutes(milliSeconds) -
TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(milliSeconds)),
TimeUnit.MILLISECONDS.toSeconds(milliSeconds) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(milliSeconds)));
I get the message :
Implicitly using the default locale is a common source of bugs:
Use String.format(Locale, ...) instead
I have no idea how to modify the code in order to implement the recommendation.
Most likely you don't need to do anything. That's a warning telling you that you didn't specify a locale for String.format, so it's using the default locale. That can cause a bug in some circumstances, but it's unlikely to in yours. If you want to be careful you can pass in an explicit locale, or you can just ignore the warning. Formatting numbers like this without any type of currency is fairly safe.
(The bugs you'll see are if the locale your device is in has specific formatting rules for things. The big one I know of that's hit me is that Turkish has a letter i who's capital symbol is different than the english letter I.)

About Locale class in Java

I'm using a TTS method on Android which takes a Locale instance as an argument. So I googled the class Locale and found some example code. But I don't understand what is different among usages below because I tested them all with a TTS method and it seems to work all the same to me.
Locale("ja")
Locale("ja_JP")
Locale("ja", "JP", "")
Locale.JAPAN
Locale.JAPANESE
Are there any differences?
The documentation for the Locale class describes this in (almost excruciating) detail. The valid language, country, and variant codes are described in ISO 639.
Here are the differences between the five examples you give:
ja simply describes the Japanese language with no country.
ja_JP specifies both the Japanese language and the country of Japan
The three parameter constructor splits off the language, country, and variant into separate arguments. Locale("ja", "JP", "") is equivalent to Locale("ja_JP") since no variant is provided.
Locale.JAPAN is a constant shortcut for ja_JP (the country of Japan).
Locale.JAPANESE is a constant shortcut for ja (the Japanese language).
What does this all mean? Well, it depends on where it is used. Locales are used with a number of different APIs, including the date-time APIs, text-to-speech APIs, and more.
In the context of text-to-speech, the locale can be used in a number of ways, such as:
Selecting the appropriate voice to use
Applying the proper inflection for certain words. Different locales may speak the same word in the same language differently.
Translating certain non-words into speech. For instance, different locales may speak numbers or fractions differently.
In general, you want to be as specific and accurate as possible when selecting a Locale.

Common datetime formats in log files

I'm looking for a list of common datetime formats used in logs (e.g. webserver, database, etc).
Even better would be a (java) library that can extract date and time from a given string ( < 10KB).
Does anyone know a good one?
this library is likely a good place to start: SimpleDateFormat
The docs contains the an introduction to the standard datetime format strings. But as #Olaf points out, you're going to need to specify what the format is beforehand or there is literally no way differentiate certain dates from one another.
Looks like what you'd want to do is construct a range of date formats that might match, apply all of them to a date string, then see which date is closest to Datetime.now().
Although this doesn't answer your question directly, but Java includes libraries for working with regular expressions. It would be pretty easy to write a library of your own based on that. I've has a lot of success extracting all sorts of data using regular expression. It would certainly be less than 10kb and would require no external dependencies other than the JDK.

Separate language and format locales in a Wicket app?

Our Wicket app needs separate UI language and number/date format locales (e.g. UI in english, Number and date format: German) per user.
If you set the session locale to say Locale.GERMAN, you get both german number and date format AND german resources (e.g. MyForm_de.properties).
We worked around this by setting the session locale to the number and date locale and then use a custom ComponentStringResourceLoader to load strings (return super.loadStringResource(clazz, key, language != null ? new Locale(language) : locale, style, variation)). However, it looks like strings are being cached because if I log on as different users, I start getting a mixture of languages.
Anyone know to control the caching (assuming that is causing the problem)? Note: I don't want to prevent caching (since that would presumably hurt performance). I guess I want to override the caching behavior so it works correctly with our custom resource loader.
Or is there a better approach altogether to solving this problem?
Here's the code we used for the custom StringResourceLoader.
ComponentStringResourceLoader myComponentStringResourceLoader = new ComponentStringResourceLoader() {
#Override
public String loadStringResource(Class<?> clazz, String key, Locale locale, String style, String variation) {
return super.loadStringResource(clazz, key, getLoggedOnUser().getUILanguageLocale(), style, variation);
}
};
getResourceSettings().getStringResourceLoaders().add(0, myComponentStringResourceLoader);
Here's the code to set the session locale (used for number and date formatting).
getSession().setLocale(getLoggedOnUser().getNumberAndDateLocale());
You can use Session's locale for i18n of the labels and either override #getLocale() or #getConverter() for the components which should use the different locale for dates. I guess you talk about TextField which needs to render its value in German locale. If so, just create GermanTextField that always returns Locale.GERMAN in its #getLocale().

How do you handle internationalization for "Your input 'xyz' is excellent!"

I would like to know what is the right way to handle internationalization for statements with runtime data added to it. For example
1) Your input "xyz" is excellent!
2) You were "4 years" old when you switched from "Barney and Freinds" to "Spongebob" shows.
The double quoted values are user data obtained or calculated at run time. My platforms are primarily Java/Android. A right solution for Western languages are preferred over weaker universal one.
Java
To retrieve localized text (messages), use the java.util.ResourceBundle API. To format messages, use java.text.MessageFormat API.
Basically, first create a properties file like so:
key1 = Your input {0} is excellent!
key2 = You were {0} old when you switched from {1} to {2} shows.
The {n} things are placeholders for arguments as you can pass in by MessageFormat#format().
Then load it like so:
ResourceBundle bundle = ResourceBundle.getBundle("filename", Locale.ENGLISH);
Then to get the messages by key, do:
String key1 = bundle.getString("key1");
String key2 = bundle.getString("key2");
Then to format it, do:
String formattedKey1 = MessageFormat.format(key1, "xyz");
String formattedKey2 = MessageFormat.format(key2, "4 years", "Barney and Friends", "Spongebob");
See also:
Trail: internationalization
Android
With regards to Android, the process is easier. You just have to put all those String messages in the res/values/strings.xml file. Then, you can create a version of that file in different languages, and place the file in a values folder that contains the language code. For instance, if you want to add Spanish support, you just have to create a folder called res/values-es/ and put the Spanish version of your strings.xml there. Android will automatically decide which file to use depending on the configuration of the handset.
See also:
Developer guide - Localization
One non-technical consideration. Embedding free data inside English phrases isn't going to look very smooth in many cultures (including Western ones), where you need grammatical agreement on e.g. number, gender or case. A more telegraphic style usually helps (e.g. Excellent input: "xyz") -- then at least everybody gets the same level of clunkiness!
I think one will probably have to define one's format string to include a "1-of-N" feature, preferably defined so as to make common cases easy (e.g. plurals). For example, define {0#string1/string2/string3} to output string1 if parameter 0 is zero or less, string2 if it's precisely 1, and string3 if it's greater than 1}. Then one could say "You have {0} {0#knives/knife/knives} in the drawer."

Categories