I have a situation in which a client for obscure reasons wants a specific locale to be in place, except for the modification that month names in lower case as per the locale should be shown in upper case (which is not a standard variant of the locale in question). I already have SimpleDateFormatter code in place referencing an instance of Locale.
My question is whether it is possibly to dynamically construct an instance of Locale based on a designated country code, but with specifically given modifications? Or, alternatively, whether it is possible to build a locale instance from scratch, specifying all details at runtime, such that a SimpleDateFormatter referencing it would change its casing of months accordingly?
Thanks in advance.
The Javadoc for LocaleServiceProvider should get you started.
Related
I need to change my Java locale to another language system-wide for work purposes, but there seems to be no easy way to do it by default. I do development for CJK applications, but changing my actual system locale to match also renames my home folders, meaning if my input method decides to stop working I would have to reboot my entire system.
I've tried setting JVM arguments (-Duser.language=ja -Duser.locale=JP) on
maven command line arguments (really not what I want but tried out of desperation)
{$project_dir}/.mvn/jvm.config (not ideal)
environment JAVA_ARGS (under /etc/environment)
maven JVM arguments in eclipse/intellij
MAVEN_OPTS
but none of them work. Pretty much at my wits end here.
To be clear I'm looking for a solution with the following criteria:
Not project specific
Doesn't require project source modification (e.g. project properties files) outside of .mvn
Doesn't involve changing my actual system locale (en_US)
Doesn't require constant maintenance (e.g. constantly add command line arguments)
So basically some kind of environment variable.
You can include these properties on your application.properties or application.yaml:
spring.mvc.locale=pt_BR
spring.mvc.locale-resolver=fixed
Changing the locale to the one you need.
These properties are used to defined the locale when the WebMvcAutoConfiguration is being configured, through the following method:
#Bean
#ConditionalOnMissingBean
#ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
You can check also the source code here
Your -Duser.locale=JP JVM argument should be -Duser.country=JP.
From Oracle technical resource on Locale:
... on some Java runtime implementations, the application user can override the host's default locale by providing this information on the command line by setting the user.language, user.country, and user.variant system properties.
(not a complete answer, but I don't have enough reputation to comment)
The JVM maintains its own current default locale. This behavior is required by the Java specifications.
Typically a JVM implementation detects the host OS default when the JVM starts up, and uses that as its own default. Later changing the host OS’ current default has no effect on the JVM. This behavior is not specified in the Java specs.
You can typically override that behavior by specifying a default locale on the command-line used to launch the JVM. You said you tried this, but did not explain why this is not a solution. This behavior is not specified in the Java specs.
Externally monitor & manipulate
You could externally monitor and manipulate the locale within Java by opening some communication path.
JMX springs to mind.
External look-up
When your app starts, it could look in an external source for an idea of what locale to use, then make that a singleton within your app.
An LDAP server is one such external place to hold such values. You would use JNDI in Java to access the server and retrieve the value.
Call Locale.setDefault
Calling Locale.setDefault immediately affects all code in all apps within the JVM. But this does not persist. You must call again when relaunching your app or JVM.
Any other code can call this as well as your code, making it unreliable. I do not recommend this approach.
You can hard-code the desired Locale by declaring a static class variable.
static final public Locale LOCALE = Locale.ITALY ;
In the lifecycle code called when your app launches, call Locale.setDefault( SomeClass.LOCALE ) ;.
Pass Locale object in your code
➥ I suggest always passing Locale explicitly as the optional argument in the various places you care about.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
Locale locale = Locale.CANADA_FRENCH ; // Pass explicitly your desired/expected `Locale`.
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDate( FormatStyle.FULL ).withLocale( locale ) ;
String output = today.format( f ) ;
mardi 11 juin 2019
Depending on the JVM’s current default locale is unreliable. As a programmer you are depending on externalities you cannot control.
The sysadmin or end-user may alter the default in deployment.
Any code in any thread of any app or library within the JVM calling Locale.setDefault immediately affects your code.
By the way, same goes for time zone, ZoneId. Better to always pass explicitly your desired/expected time zone.
Also, if the locale or time zone is crucial, best to confirm with the user.
You can try settig jvm parameters like (presudocode)
First way, you can do it like this-
java -Duser.country=CA -Duser.language=fr ........
Second way would be to call method
Locale.setDefault(Locale)
above method will set it jvm wise locale.
Third way, as per docs
Using an Explicit Locale
In some computing environments, applications use only a single locale
throughout their life cycle. In other environments, applications use a
global locale that can be changed. Those environments allow you to
programmatically change the global locale preference, which remains in
effect until you explicitly change it again. The Java application
environment is unique, providing you with the ability to use a variety
of locales throughout your application in any way you require.
Multinational companies have customers all around the globe. This
means that both their customers and employees may speak different
languages and have different expectations for how the company and its
software should behave. Moreover, it is entirely possible, even
common, to have a French employee handle a sales record for an Italian
customer. In those situations, you will need absolute control over
which locale your business and user interface objects use to
manipulate and represent data. Your application may need to print
sales receipts using Italian date and currency formats, yet sort
customer lists for an English sales employee. The combinations are far
too numerous to list, but Java technology provides you the flexibility
to handle that complexity.
In order to get the most flexibility, you must explicitly request
support for a target locale for each locale-sensitive class that you
use. That means you must track the locale preferences for multiple
aspects of the application or assign locale preferences to different
users and customers.
If you have tracked the user's locale preference, you would create
instances of locale-sensitive classes by explicitly providing a locale
in a constructor or creation method. Imagine that a preferences object
stores your customer's locale choice:
Locale userLocale = preferences.getLocale();
NumberFormat nf = NumberFormat.getInstance(userLocale);
So, in here, you can store your customer locale prefernce in this Preference object api, then do the required formatting operation etc.
What you can do is, set one global locale or leave one default locale.
And whenever required, set explicitly the required "locale" in the method.
Kindly go throw the following links as well-
https://www.top-password.com/blog/tag/change-system-locale-windows-command-line/
https://www.oracle.com/technetwork/articles/javase/locale-140624.html#using
The only way that I've found that works for me is setting LANG=ja_JP.UTF-8 as an actual system environment variable on my IDEs that kicks in after boot (both eclipse and intellij provide this under run configurations). But I really really dislike this approach.
The documentation for BreakIterator.getWordInstance() has options to use it with the Locale parameter, presumably because different locales' end results may vary for methods like (WordInstance, LineInstance, SentenceInstance, CharacterInstance)
But, when I do not use this parameter, I still get the same results as I get when calling it with any Locale in getAvailableLocales().
Is there some pattern, String, or Locale which actually causes these methods to give different results?
I believe all "western" languages have the same rules.
Cursory scan shows that locale th (Thai) has it's own rules, given in file /sun/text/resources/th/WordBreakIteratorData_th inside .../jre/lib/ext/localedata.jar.
It's a binary file, so I don't know what it says, and even if I could understand the file, not knowing Thai, I still wouldn't understand it.
Java has two overloads each for String.toLowerCase and toUpperCase. One of the overloads takes a Locale as a parameter while the other one takes no parameters and uses the default locale (Locale.getDefault()).
The parameterless variants might not work as expected because case conversion respects internationalization, and the default locale is system dependent. Most notably, the lower case i is converted to an upper case dotted İ in the Turkish locale.
What is the purpose of these methods? Do the parameterless variants have any legitimate use? Or perhaps they were just a design mistake? (Not unlike several I/O APIs that use the system default character encoding by default.)
I think they're just convenience methods that will work most of the time, since apps that really need I18n are probably a small minority in the universe of java apps in the world.
If you hardcode a unix path for a File name in a java program and try to run in a windows box, you will also get wrong results and it's not java's fault.
I guess that's an implementation of write once run anywhere principle.
It makes sense, cause you can provide the default locale at JVM startup as one of the runtime parameters.
Furthermore, Java runtime has got a bunch of similar formatting methods for Dates and Numbers. (SimpleDateFormat, NumberFormat etc)
Several blog posts suggest that default locales and charsets indeed were a design mistake and have no meaningful use.
I'd like to produce Partials from Strings, but can't find anything in the API that supports that. Obviously, I can write my own parser outside of the Joda-Time framework and create the Partials, but I can't imagine that the API doesn't already have the ability to do this.
Use of threeten (JSR-310) would be an acceptable solution, but it doesn't seem to support Partials. I don't know whether that is due to its alpha status, or whether the Partial concept is handled in a different manner, which I haven't discovered.
What is the best way to convert a String (2011, 02/11, etc) into a Partial?
I've extended DateTimeParserBucket. My extended class intercepts calls to the saveField() methods, and stores the field type and value before delegating to super. I've also implemented a method that uses those stored field values to create a Partial.
I'm able to pass my bucket instance to DateTimeParser.parseInto(), and then ask it to create the Partial.
It works, but I can't say I'm impressed with Joda-Time - given that it doesn't support parsing Partials out of the box. The lack of DateTimeFormatter.parsePartial(String) is a glaring omission.
You have to start by defining the valid format for Partials which you will be accepting. There is no class which will just take text and infer the best possible match for a Partial. It's way too subjective based on locale, user preference, etc. So there's no way of getting around making a list of all of the valid formats for input. It will be very difficult to make these all mutually exclusive for each other, so there should be priorities. For example, you might want mm/dd and mm/yy to both be valid formats. If I give you the string 02/11, which one should have priority?
Once you've determined exactly the valid formats, you should use DateTimeFormat.forPattern to create a DateTimeFormatter for each one. Then you can use each formatter to try to parseInto a MutableDateTime. Then, go through each field in the MutableDateTime and transfer the value into a Partial.
Unfortunately, there is no better way to handle this in the Joda library.
The ISODateTimeFormat class allows partial printing. As you say, there is no parsing method on DateTimeFormatter (although you can parse to a LocalDate and interpret that).
ThreeTen/JSR-310 has the DateTimeFields class which replaces Partial. Parsing of partials into a CalendricalMerger is supported, however that may not be convertable back into a DateTimeFields yet.
I am looking for a way to add more Locales to the Locales available in Java 1.6. But the Locales I want to create do not have ISO-3166 country codes, nor ISO-639 language codes. Is there any way to do this anyways? The Locales I want to add only differ in the language names, but the smaller an ethnic group is, the more picky they get about their identity ;-)
So I thought about extending an existing Locale, something like
UserDefinedLocale extends Locale {
UserDefinedLocale (Locale parentLocale) {...}
}
but java.util.Locale is final, which makes it especially hard to hack something around...
So, is the idea that the list of Java Locales is exhaustive? Am I the first to miss some more Locales?
Read the javadoc for java.util Locale.
It says :
"Create a Locale object using the constructors in this class: "
It also says :
"Because a Locale object is just an identifier for a region, no validity check is performed when you construct a Locale"
It also says :
"A Locale is the mechanism for identifying the kind of object (NumberFormat) that you would like to get. The locale is just a mechanism for identifying objects, not a container for the objects themselves"
And finally, the javadoc for the getAvailableLocales() method says :
"The returned array represents the union of locales supported by the Java runtime environment and by installed LocaleServiceProvider implementations"
So you just have to invent a language code which is not in the standard list, and use it as an identifier for your locale.
See this answer:
...You can plug in support for additional locales via the SPIs (described here). For example, to provide a date formatter for a new locale, you would do it by implementing a DateFormatProvider service. You might be able to do this by decorating an existing implementation - I'd have a look at the ICU4J library to see if it provides the support you want.