JavaScript's standard API to get the runtime's default locale? - javascript

In order to determine the current locale I found different approaches:
Being in the browser, most people suggest looking at the HTTP headers (Accept-Language)
Some people suggest consulting navigator.language
Being in the backend (Node.js) and apart of HTTP, it is suggested to consult the (system dependent) process.env
On the other side, the ECMAScript Internationalization API defines the locales argument to each of the Intl constructors as optional:
If the locales argument is not provided or is undefined, the runtime's
default locale is used.
So, it seems as if there should be a browser-independent and OS independent way to get "the runtime's default locale".
Is there a more straight forward way to get the runtime's default locale than
new Intl.NumberFormat().resolvedOptions().locale
?
The question How/Where does JavaScript detect the default locale? is different as it asks for the implementation of detecting the default locale (in a browser host). In contrast to that, my question is not about implementation but about the existence of a standard API.

I'm not aware of a more straight-forward approach, but as you have already pointed out,
new Intl.NumberFormat().resolvedOptions().locale is a solution
DefaultLocale is an abstract operation, which might or might not be implemented in the future.
Hence, I would argue for polyfilling this function as:
if (typeof DefaultLocale === "undefined") {
function DefaultLocale() {
return new Intl.NumberFormat().resolvedOptions().locale;
}
}
So, your code will reasonably assume the existence and call this function. In some point in the future, when this function is implemented in a standard manner, you will be able to clean up by removing the chunk from above.

Just adding this as a choice, doesn't seem to be much better than the shim from Lajos because I guess one would need to have a request and to interpret the q (see the MDN excerpt below).
If you can get hold of a request's headers, most browsers inject:
Accept-Language
en-US,en;q=0.5
Accept-Language
en-US,en;q=0.9,ro;q=0.8,en-GB;q=0.7
From MDN docs https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language :
A language tag (which is sometimes referred to as a "locale identifier"). This consists of a 2-3 letter base language tag
representing the language, optionally followed by additional subtags
separated by '-'. The most common extra information is the country or
region variant (like 'en-US' or 'fr-CA') or the type of alphabet to
use (like 'sr-Latn'). Other variants like the type of orthography
('de-DE-1996') are usually not used in the context of this header.
Any language; '*' is used as a wildcard.
;q= (q-factor weighting) Any value placed in an order of preference expressed using a relative quality value called weight.
The way I understand it, the highest weight (q-value) should be prefered, if available

Related

JavaScript encrypted xml throws error in Java application decryption: Given final block not properly padded. Such issues can arise if a bad key is [duplicate]

Does anyone know what the default Java crypto behavior is for:
SecretKeySpec localSecretKeySpec = new SecretKeySpec(arrayOfByte, "AES");
Cipher localCipher = Cipher.getInstance("AES");
Specifically I am looking to understand how those classes generate the IV, as well as what is the default encryption mode when just specifying "AES". Thanks.
For Oracle JDK 7 (tested), the default cipher for AES is AES/ECB/PKCS5Padding. The Java Security documentation doesn't mention about this though (http://docs.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html#algspec), have to do some JUnit testing to find out.
The details are provider specific. The JCA Reference Guide says that:
(Creating a Cipher Object) If no mode or padding is specified, provider-specific default values for the mode and padding scheme are used. For example, the SunJCE provider uses ECB as the default mode, and PKCS5Padding as the default padding scheme for DES, DES-EDE and Blowfish ciphers. This means that in the case of the SunJCE provider: Cipher.getInstance("DES") and Cipher.getInstance("DES/ECB/PKCS5Padding") are equivalent statements.
I would always use the full form (algorithm/mode/padding), not only because I think that leaving out such "details" to the implementation is bad practice, but also for achieving a ciphertext that is independent of the chosen provider (one usually encrypts for storage/transmission, then one cannot be sure that the same provider will be used later/on the other end).
Those details are provider specific, and relying on the default mode and padding can be very dangerous. If you are interested in what the values that the default provider currently bundled with Java uses you'll have to hunt down the source code for the algorithm in question. For instance, the default values it uses for the RSA algorithm are here. Also, the Java™ Cryptography Architecture (JCA) Reference Guide has quite a bit of information that could answer some of you other questions.
It depends on the Providers. Different providers might have different default parameters. This is the link for Java 8.
https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html#ciphertrans
The javax.crypto.Cipher.getInstance(String transformation) factory
method generates Ciphers using transformations of the form
algorithm/mode/padding. If the mode/padding are omitted, the SunJCE
and SunPKCS11 providers use ECB as the default mode and PKCS5Padding
as the default padding for many symmetric ciphers.
It is recommended to use transformations that fully specify the
algorithm, mode, and padding instead of relying on the defaults.
Note: ECB works well for single blocks of data and can be
parallelized, but generally should not be used for multiple blocks of
data.
Therefore, you should not just use AES but specify the mode and padding. Furthermore, although the getInstance method could have another parameter for the provider, this is not recommended because
applications are tied to specific providers that may not be available
on other Java implementations

How do I use the "best fit" locale in JavaScript?

My understanding of the problem so far:
I'm reading this MDN document which says:
The locales argument, after stripping off all Unicode extensions, is interpreted as a prioritized request from the application. The runtime compares it against the locales it has available and picks the best one available. Two matching algorithms exist: the "lookup" matcher follows the Lookup algorithm specified in BCP 47; the "best fit" matcher lets the runtime provide a locale that's at least, but possibly more, suited for the request than the result of the Lookup algorithm. If the application doesn't provide a locales argument, or the runtime doesn't have a locale that matches the request, then the runtime's default locale is used. The matcher can be selected using a property of the options argument (see below).
When I read this, it appears that I can use "lookup" and "best fit" the same way, sometimes getting different results.
However
I can do:
new Intl.DateTimeFormat('lookup', options).format(date)
But not:
new Intl.DateTimeFormat('best fit', options).format(date)
I'm using a current version of Firefox (65.0.1 64-bit on Ubuntu), and Firefox doesn't have any open bugs on the issue as far as I can tell, but I get a RangeError when I use 'best fit'.
Remaining questions:
Am I supposed to be able to give the 'best fit' as the locale argument, or can I only use it as the localeMatcher in the options argument? If I can only use 'best fit' inside options, then what should I specify as the locale, given that locale is required when options is present?
Or should I just open a ticket in Bugzilla?
In your first example, a string is passed to the Intl.DateTimeFormat so it appears to work. But all it does is not recognize the string as a valid locale and then uses the default.
The second example doesn't work because the string is not formatted in accordance with BCP 47.
You've misinterpreted the API documentation. This:
The locales argument must be either a string holding a BCP 47 language
tag, or an array of such language tags. If the locales argument is not
provided or is undefined, the runtime's default locale is used.
clearly indicates the first argument should be a string or (array of strings) that is/are a locale identifiers.
Then this:
The options argument must be an object with properties that vary
between constructors and functions.
So your call to the should look like this:
new Intl.DateTimeFormat([],{localeMatcher: "best fit"}).format(date)

How/Where does JavaScript detect the default locale?

Today, the 11th of September, 2017, JavaScript's toLocaleDateString() method is outputting 9/11/2017 for me. But I am in the UK, so the formatting is wrong in this case. The MDN Web Docs tell me that this method returns "a formatted string in the default locale".
So, where/how is JavaScript detecting my default locale? Where is this set, or what does it depend on, and (how) can I change it?
Edited to add: I'm using Firefox 55.0.3 on Windows 10 if that makes any difference.
To summarize shortly, detecting the current locale is implementation dependent and may differ from environment to environment. Your default language may also depend on the installer you've used to install your browser.
The not so short version:
Following the ECMAScript spec, conforming browsers (and other environments, such as Node.js) should implement localization following the ECMAScript Internationalization API (ECMA-402), which only outlines the following for getting the default locale:
The DefaultLocale abstract operation returns a String value representing the [...] language tag for the host environment’s current locale.
This means that getting the default locale is implementation dependent and can differ from browser to browser. This is intentional, as it allows browser vendors to keep their current, differing implementations to stay conforming without much fuss.
While it's true that it would be nice to have this standardized as well, it's more beneficial to get everyone on board for a broad spec first and then work out the little kinks later.
Most modern browsers allow you to change your current default locale in their preferences (Chrome shown):
I checked JavaScript date and time formatting in Chrome, Firefox, and Edge on my Windows 10 PC, with interesting results. My language tag should be "en-NZ', and I thought the locale behavior would follow accordingly.
Of the three browsers, only Edge had picked up the correct language tag by default, presumably from the OS, while Chrome and Firefox both defaulted to en-US. Edge also defaults to using the correct locale settings.
It seems I can influence the locale in Chrome by changing language in Advanced Settings to en-NZ, but the default locale behavior I get is as for en-GB. Firefox doesn't seem to care what my preferred language is for locale behavior, which depends only on the language "used to display menus, messages, and notifications from Firefox". The only English language options for that are US, Canada, or UK.
In Chrome and Firefox the only way to ensure the correct locale behavior seems to be to explicitly specify it in the JavaScript code.
You can pass locale as parameter. See the example below:
var date = new Date().toLocaleDateString("en-GB");

i18n: Access locale resolution logic in JavaScript

I'm developing and internationalized Single Page App with 2 sorts of localized text:
'static' text, typically text in my HTML templates.
'dynamic' text, i.e text that lives in the database, typically the description of a product on an e-commerce site.
It's type 2 I'm having trouble with. Say my app officially supports English, French and German, and I get from my database an object such as :
{
description: {
'en': "It's an awesome product.",
'en_UK': "This product is ace.",
'fr': "C'est un excellent produit."
// German's missing
}
}
Now the challenge is to dynamically choose what locale should be chosen for display, given the user's locale and what locales are available in this particular object.
I assume most i18n JavaScript libraries have their own 'locale resolution' logic built-in, but I haven't found one that exposes this logic for the client to use.
Does anyone know a JS library that addresses this, or a good way to solve this issue? (if it's AngularJs-compatible, it's even better).
Thanks in advance!
Disclaimer: I'm a co-author of L20n and one of the developers of
l10n.js used in Firefox OS.
The term that's commonly used to describe this logic is language negotiation.
Most localization libraries should have some sort of language negotiation algorithm included. It can be as basic as trying to match the value of navigator.language with a list of available languages. More sophisticated approaches will look at both the language tag (en in en-US) and the region tag (US in en-US) to try to find a best match.
There's a proposal to expose a language negotiation method on the ECMAScript's Intl object, but for now it's not possible to use its internal logic for this purpose.
Getting the list of languages preferred by the user is not as easy as it should be. There's navigator.language in most browsers (which is the user's preferred language in Firefox and the language of the browser UI in Chrome), navigator.userLanguage in Internet Explorer, and the new navigator.languages which is an ordered list of user's preferred languages.
A server-side alternative is to use the Accept-Language header of the HTTP request which currently is the most reliable way of finding out what the user's preferences are.
Once you have the list of user's preferred languages you can perform the language negotiation.
Here are a few examples of libraries that perform language negotiation:
in-browser-language,
l10n.js used in Firefox OS,
a non-standard extension of the ECMA-402 Intl object which adds Intl.prioritizeLocales.
For your particular use-case, you can choose to do one of the two following things:
perform the language negotiation on the client side using navigator.language || navigator.userLanguage and send a request to the database specifying which language you're interested in, or
send the request with the user's Accept-Language header and perform the language negotiation on the server side, and then query the database for the correct translation.
Both solutions have the benefit of not sending the entire set of translations to the client when only one will be eventually used.
For solution #1, given that you're using Angular, I can suggest using L20n 1.0.x which integrates with Angular via the ng-l20n module. You should be able to use the supportedLocales property to get the negotiated list of languages and use the first element of that list to query the database.
For solution #2, it all depends on your server-side setup, but if you're using node.js, you can try using one of the following modules:
the afore-mentioned in-browser-language,
locale.
Staś Małolepszy's answer is a good reference of the resources available for this problem domain.
However, I found that none of these libraries suited my needs (either because their language negotiation logic was too simplistic, or because it wasn't really exposed).
Therefore, I implemented my own custom solution for language negotiation. You can experiment with it in this Plunkr: http://plnkr.co/edit/Cfv49ZcQWJcqwOXYcjtw?p=preview
The API is a function negotiate(availableLocales, requestedLocales, defaultLocale), a bit similar to the ECMAScript proposal (with the difference that it returns a single locale value, not a list).
// simple cases
negotiate(["fr"], ["de","fr"], 'en'); // => fr
negotiate(["en"], ["de","en-US","en"], 'en'); // => en
// less natural cases, where the solution is more opinionated
negotiate(["fr-FR"], ["fr"], 'en'); // => fr-FR
negotiate(["en","en-UK","fr"], ["fr-FR"], 'en'); // => fr
negotiate(["fr","de"], ["fr-FR","de"], 'en'); // => fr
I made the choice to account for 'locale inheritance' (e.g en-US is derived from en) in a non-trivial, opinionated manner . I do not claim this is in compliance with whatever standards exist on this topic.
It surprised me that I couldn't find any library that provides this sort of functionality. My best explanation is that i18n of dynamic content isn't needed that often.
Finally, as to where I get the list of requested languages, as I was in an Single Page App configuration I chose to send an AJAX request to my server, with the content of the Accept-Language header in the response.

Locale: Browser or OS Setting?

What does it mean when a "locale" is set to e.g. Japanese? Does it mean the browser is set to be ready to recognize Japanese characters? Or, is it more related to an OS setting?
Related to i18n (internationalization and localization), how do we detect that a user who is visiting our site has a e.g. Japanese locale using JavaScript? Will the following simple check suffice?
var userLocale = navigator.language || navigator.userLanguage;
if (userLocale.toLowerCase() == 'ja-jp') { ... }
Can a Japanese locale browser return something else rather than ja-jp?
Thanks beforehand.
First we need to define what Locale is. In the context you are using it is a ISO639 Language Identifier optionally followed by ISO3166 Country Identifier. This is used to determine end user's preferences (like language of localized content or date and time formats and number formats).
Now, Locale could be set in multiple places. OS usually has multiple settings, for example keyboard layout, formatting preferences, language preferences, code pages (for non-Unicode programs), etc.
Apart from that, web browsers usually allow you to choose your own preferences (Safari is an exception here). These preferences are send along with each request to the web server, via HTTP Accept-Language header. This is something you should somehow read on the server side (which unfortunately means some server-side code in PHP, C#, Java, whatever) and maybe passed to your client-side script.
I must state here that something like navigator.language is not the way to go for two reasons:
This is not cross-browser compatible, that is other web browsers would require different code. That is if they allow reading this information in the first place.
This setting usually refers to web browser's language (the language web browser's user interface is translated to) and has nothing to do with actual user's preference.
So to answer your question: no, this check will not suffice.
That is mostly an OS/browser setting, controlling e.g. language of the OS, date/time format, decimal point/comma, etc. - in other words, settings that vary in different locales of the world. This has no direct correlation with font/character support.
As far as I know, ja-jp is the only standardized Japanese locale/language combination; but as #Siku-siku.com suggested in the comments "(based on real testings using Japanese version of IE/WinXP) also check for ja because that's one of the available options in the IE language setting."

Categories

Resources