Con un navegador, ¿cómo sé qué separador decimal usa el sistema operativo?

Estoy desarrollando una aplicación web.

Necesito mostrar algunos datos decimales correctamente para que se puedan copiar y pegar en una determinada aplicación GUI que no esté bajo mi control.

La aplicación GUI es sensible a la configuración regional y acepta solo el separador decimal correcto que se establece en el sistema.

Puedo adivinar el separador decimal de Accept-Language y la suposición será correcta en el 95% de los casos, pero a veces falla.

¿Hay alguna manera de hacerlo en el lado del servidor (preferiblemente, para que pueda recostackr estadísticas), o en el lado del cliente?

Actualizar:

El objective de la tarea es hacerlo automáticamente.

De hecho, esta aplicación web es un tipo de interfaz en línea para una GUI heredada que ayuda a completar los formularios correctamente.

El tipo de usuarios que lo usan en su mayoría no tiene idea de qué es un separador decimal.

La solución Accept-Language está implementada y funciona, pero me gustaría mejorarla.

Actualización2:

Necesito recuperar una configuración muy específica: separador decimal establecido en Control Panel / Regional and Language Options / Regional Options / Customize .

Me ocupo de cuatro tipos de sistemas operativos:

  1. Windows rusa con una coma como DS (80%).
  2. Inglés Windows con un período como DS (15%).
  3. Windows rusa con un período como DS para hacer que las aplicaciones en inglés mal redactadas funcionen (4%).
  4. Inglés Windows con una coma como DS para hacer que las aplicaciones rusas mal escritas funcionen (1%).

El 100% de los clientes están en Rusia y la aplicación heredada trata con los formularios emitidos por el gobierno ruso, por lo que pedir un país arrojará el 100% de la Federación Rusa y GeoIP generará el 80% de la Federación Rusa y el 20% de otros (incorrecto) respuestas

Aquí hay una función simple de JavaScript que devolverá esta información. Probado en Firefox, IE6 e IE7. Tuve que cerrar y reiniciar mi navegador entre cada cambio a la configuración en Panel de control / Regional y Opciones de idioma / Opciones regionales / Personalizar. Sin embargo, recogió no solo la coma y el punto, sino también cosas extrañas y personalizadas, como la letra “a”.

 function whatDecimalSeparator() { var n = 1.1; n = n.toLocaleString().substring(1, 2); return n; } 
 function whatDecimalSeparator() { var n = 1.1; n = n.toLocaleString().substring(1, 2); return n; } console.log('You use "' + whatDecimalSeparator() + '" as Decimal seprator'); 

Pregúntele al usuario, no adivine. Ten una configuración para esto en tu aplicación web.

Editado para agregar:

Creo que está bien adivinar la configuración predeterminada que funciona bien, digamos, el 95% de las veces. Lo que quise decir es que el usuario debería poder anular las conjeturas que haya hecho el software. Ya me he sentido frustrado muchas veces cuando un software intenta ser demasiado inteligente y no permite ser corregido.

 function getDecimalSeparator() { //fallback var decSep = "."; try { // this works in FF, Chrome, IE, Safari and Opera var sep = parseFloat(3/2).toLocaleString().substring(1,2); if (sep === '.' || sep === ',') { decSep = sep; } } catch(e){} return decSep; } 

Puedo adivinar el separador decimal de Accept-Language y la suposición será correcta en el 95% de los casos, pero a veces falla.

Esta es la OMI el mejor curso de acción. Para manejar las fallas, agregue un enlace para configurarlo manualmente junto al área de visualización.

Por qué no

 0.1.toLocaleString().replace(/\d/g, '') 

La recuperación de separadores para la configuración regional actual o determinada es posible utilizando Intl.NumberFormat#formatToParts .

 function getDecimalSeparator(locale) { const numberWithDecimalSeparator = 1.1; return Intl.NumberFormat(locale) .formatToParts(numberWithDecimalSeparator) .find(part => part.type === 'decimal') .value; } 

Solo funciona para los navegadores compatibles con la API Intl . De lo contrario, requiere un polyfill Intl

Ejemplos:

 > getDecimalSeparator() "." > getDecimalSeparator('fr-FR') "," 

Prima:

Podríamos extenderlo para recuperar el separador decimal o grupal de una localidad determinada:

 function getSeparator(locale, separatorType) { const numberWithGroupAndDecimalSeparator = 1000.1; return Intl.NumberFormat(locale) .formatToParts(numberWithGroupAndDecimalSeparator) .find(part => part.type === separatorType) .value; } 

Ejemplos:

 > getSeparator('en-US', 'decimal') "." > getSeparator('en-US', 'group') "," > getSeparator('fr-FR', 'decimal') "," > getSeparator('fr-FR', 'group') " " 

Creo que debes confiar en JavaScript para darte la configuración regional.
Pero aparentemente JS no tiene acceso directo a esta información.
Veo que Dojo Toolkit se basa en una base de datos externa para encontrar la información de configuración regional, aunque puede que no tenga en cuenta los cambios de configuración, por ejemplo.
Otra solución que veo es tener un pequeño applet silencioso de Java que consulte esta información del sistema, y ​​JavaScript para que salga de Java.
Puedo dar más información si no sabes cómo hacerlo (si quieres ir por esta ruta intrincada, por supuesto).

[EDITAR] Así que actualicé mi conocimiento de soporte de localización en Java …
A diferencia de lo que pensé originalmente, no tendrá directamente el separador decimal o los miles de caracteres separadores directamente, como lo haría con el separador de línea o el separador de ruta: en cambio, Java ofrece API para formatear los números o las fechas que proporciona.
De alguna manera, tiene sentido: en Europa a menudo se pone el símbolo de moneda después del número, algunos países (¿India?) Tienen una regla más compleja para separar los dígitos, etc.

Otra cosa: Java encuentra correctamente la configuración regional actual del sistema, pero no toma información de allí (tal vez por las razones anteriores). En cambio, usa su propio conjunto de reglas. Entonces, si tiene una configuración regional en español donde reemplazó el separador decimal con un signo de exclamación, Java no lo usará (pero tal vez tampoco su aplicación, de todos modos …).

Así que estoy escribiendo un applet que expone un servicio (funciones) a JavaScript, lo que permite dar formato a los números en la configuración regional actual. Puede usarlo como tal, usando JavaScript para formatear números en el navegador. O puede simplemente alimentarlo con un número de muestra y extraer los símbolos de allí, usándolos localmente o devolviéndolos al servidor.

Termino y pruebo mi applet y la publico allí pronto.

De acuerdo, tengo algo que mostrar, más una prueba de concepto que un producto terminado, pero debido a la falta de especificaciones precisas, lo dejo así (o lo sobre-diseñaré). Publico en un mensaje separado porque será un poco largo. Aproveché la oportunidad para probar un poco más jQuery …

El código de Java: GetLocaleInfo.java

 import java.applet.*; import java.util.Locale; import java.text.*; public class GetLocaleInfo extends Applet { Locale loc; NumberFormat nf; NumberFormat cnf; NumberFormat pnf; // For running as plain application public static void main(String args[]) { final Applet applet = new GetLocaleInfo(); applet.init(); applet.start(); } public void init() // Applet is loaded { // Use current locale loc = Locale.getDefault(); nf = NumberFormat.getInstance(); cnf = NumberFormat.getCurrencyInstance(); pnf = NumberFormat.getPercentInstance(); } public void start() // Applet should start { // Following output goes to Java console System.out.println(GetLocaleInformation()); System.out.println(nf.format(0.1)); System.out.println(cnf.format(1.0)); System.out.println(pnf.format(0.01)); } public String GetLocaleInformation() { return String.format("Locale for %s: country=%s (%s / %s), lang=%s (%s / %s), variant=%s (%s)", loc.getDisplayName(), loc.getDisplayCountry(), loc.getCountry(), loc.getISO3Country(), loc.getDisplayLanguage(), loc.getLanguage(), loc.getISO3Language(), loc.getDisplayVariant(), loc.getVariant() ); } public String FormatNumber(String number) { double value = 0; try { value = Double.parseDouble(number); } catch (NumberFormatException nfe) { return "!"; } return nf.format(value); } public String FormatCurrency(String number) { double value = 0; try { value = Double.parseDouble(number); } catch (NumberFormatException nfe) { return "!"; } return cnf.format(value); } public String FormatPercent(String number) { double value = 0; try { value = Double.parseDouble(number); } catch (NumberFormatException nfe) { return "!"; } return pnf.format(value); } } 

Un ejemplo de página HTML que utiliza el applet anterior: GetLocaleInfo.html

       

Page to demonstrate how JavaScript can get locale information from Java

This browser does not have Java enabled.
Get the latest Java plug-in here (or enable Java support).

Click on the button to format the table content to the locale rules of the user.

Synthetic View
NameValueCostDiscount
Foo3.141592621.360.196
Bar159263.14330.33
Baz1592612.990.05
Doh0.014159265.10.1

Probado en Firefox 3.0, IE 6, Safari 3.1 y Opera 9.50, en Windows XP Pro SP3. Funciona sin problemas con los dos primeros, en Safari tengo un extraño error después de la llamada a init ():

 java.net.MalformedURLException: no protocol: at java.net.URL.(Unknown Source) at java.net.URL.(Unknown Source) at java.net.URL.(Unknown Source) at sun.plugin.liveconnect.SecureInvocation.checkLiveConnectCaller(Unknown Source) at sun.plugin.liveconnect.SecureInvocation.access$000(Unknown Source) at sun.plugin.liveconnect.SecureInvocation$2.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at sun.plugin.liveconnect.SecureInvocation.CallMethod(Unknown Source) 

pero todavía funciona.

No puedo hacer que funcione con Opera: el applet se carga correctamente, como puedo ver el rastro de la llamada de init () en la consola de Java, no tengo errores cuando JavaScript llama a las funciones de Java (excepto si agrego y llamo a un método obteniendo un parámetro JSObject, curiosamente), pero las funciones Java no son llamadas (agregué rastro de las llamadas).
Creo que Liveconnect funciona en Opera, pero todavía no veo cómo. Investigaré un poco más.
[Actualización] Quité las referencias al archivo jar no existente (que no detiene otros navegadores) y obtuve un rastro de las llamadas, pero no actualiza la página.
Mmm, si hago una alert(applet.GetLocaleInformation()); Obtuve la información, por lo que podría ser un problema de jQuery.

Incluso si supiera en qué configuración regional se está ejecutando esta “Aplicación GUI”, aún debe averiguar cómo obtiene la configuración regional actual y cómo determina el separador decimal.

No sé cómo se hace en una Mac, pero en las aplicaciones de Windows se supone que interrogan las preferencias del usuario establecidas a través del Panel de control. Es bastante posible que esta misteriosa aplicación ignore esas configuraciones y use su propia configuración interna.

O tal vez estén tomando el lugar actual e infiriendo el rest, en lugar de que se lo digan.

Incluso entonces, en inglés, los números se dan en grupos de 3 dígitos, con una coma que separa los grupos. es decir:

 5,197,359,078 

A menos que el número sea un número entero que contenga un número de teléfono :

 519-735-9078 

A menos que, por supuesto, el número era un número entero que contiene un número de cuenta :

 5197359078 

En ese caso, has vuelto a la lógica reemplazada por encoding rígida.

Editar: se eliminó el ejemplo de moneda, ya que la moneda tiene sus propias reglas de formato.

Utilizando otras respuestas de personas compilé las siguientes funciones de utilidad de separadores de decimales y miles:

 var decimalSeparator = function() { return (1.1).toLocaleString().substring(1, 2); }; var thousandSeparator = function() { return (1000).toLocaleString().substring(1, 2); }; 

¡Disfrutar!

“¿Hay alguna forma de hacerlo en el servidor (preferiblemente, para que pueda recostackr estadísticas), o en el lado del cliente?”

No, no puedes. Esa GUI está mirando algunas configuraciones específicas del usuario o de la máquina. En primer lugar, probablemente no sepa en qué configuración está buscando esta interfaz de usuario. En segundo lugar, con una aplicación web probablemente no podrá verificar esta configuración (clienteide -> Javacsript).

Otra posible solución: puede utilizar algo como GeoIP (ejemplo en PHP) para determinar la ubicación del usuario y decidir en función de esta información.