Tworzę aplikację internetową.
Muszę poprawnie wyświetlić niektóre dane dziesiętne, aby można było je skopiować i wkleić do określonej GUI
aplikacji, nad którą nie mam kontroli.
Aplikacja GUI jest wrażliwa na ustawienia regionalne i akceptuje tylko prawidłowy separator dziesiętny ustawiony w systemie.
Domyślam się, że separator dziesiętny od Accept-Language
i przypuszczenie będzie poprawne w 95% przypadków, ale czasami się nie udaje.
Czy jest jakiś sposób, aby to zrobić po stronie serwera (najlepiej, abym mógł zbierać statystyki), czy po stronie klienta?
Aktualizacja:
Celem zadania jest robienie tego automatycznie.
W rzeczywistości ta aplikacja internetowa jest rodzajem interfejsu online do starszego GUI, który pomaga poprawnie wypełniać formularze.
Użytkownicy, którzy go używają, najczęściej nie mają pojęcia, czym jest separator dziesiętny.
Accept-Language
Rozwiązanie jest wdrożony i działa, ale chciałbym, aby ją poprawić.
Aktualizacja2:
Muszę pobrać bardzo konkretne ustawienie: ustawiono separator dziesiętny Control Panel / Regional and Language Options / Regional Options / Customize
.
Mam do czynienia z czterema rodzajami systemów operacyjnych:
- Rosyjski Windows z przecinkiem jako DS (80%).
- Angielski Windows z kropką jako DS (15%).
- Rosyjski Windows z okresem jako DS, aby źle napisane angielskie aplikacje działały (4%).
- Angielski Windows z przecinkiem jako DS, aby źle napisane rosyjskie aplikacje działały (1%).
Wszyscy klienci w 100% znajdują się w Rosji, a starsza aplikacja dotyczy formularzy wydanych przez rosyjski rząd, więc zapytanie o kraj da 100% Federacji Rosyjskiej, a GeoIP zapewni 80% Federacji Rosyjskiej i 20% innych (niepoprawnych) odpowiedzi.
źródło
DecimalSeparator
(np,,
.). W systemie WindowsLOCALE_SDECIMAL
separator dziesiętny może zawierać do trzech znaków. (Dlatego nie działa na moim komputerze). W takim przypadku lepiej jest użyćAccept-Language
przeglądarki. Co nadal nie wyjaśnia możliwości określenia własnego,DecimalSeparator
np.\o/
n = /^1(.+)1$/.exec(n.toLocaleString())[1]
zrobiłby to i jest łatwiejsze niż użycieAccept-Language
nagłówka.Pobieranie separatorów dla aktualnego lub danego locale jest możliwe za pomocą
Intl.NumberFormat#formatToParts
.function getDecimalSeparator(locale) { const numberWithDecimalSeparator = 1.1; return Intl.NumberFormat(locale) .formatToParts(numberWithDecimalSeparator) .find(part => part.type === 'decimal') .value; }
Działa tylko w przeglądarkach obsługujących Intl API . W przeciwnym razie wymaga wypełnienia Intl
Przykłady:
> getDecimalSeparator() "." > getDecimalSeparator('fr-FR') ","
Premia:
Możemy przedłużyć go odzyskać albo po przecinku lub grupy separator danej lokalizacji:
function getSeparator(locale, separatorType) { const numberWithGroupAndDecimalSeparator = 1000.1; return Intl.NumberFormat(locale) .formatToParts(numberWithGroupAndDecimalSeparator) .find(part => part.type === separatorType) .value; }
Przykłady:
> getSeparator('en-US', 'decimal') "." > getSeparator('en-US', 'group') "," > getSeparator('fr-FR', 'decimal') "," > getSeparator('fr-FR', 'group') " "
źródło
Intl
jest obsługiwany nawet w IE 11: caniuse.com/#feat=internationalizationZapytaj użytkownika, nie zgaduj. Skonfiguruj to w swojej aplikacji internetowej.
Edytowano, aby dodać:
Myślę, że można zgadnąć domyślne ustawienie, które działa prawidłowo, powiedzmy, w 95% przypadków. Chodziło mi o to, że użytkownik powinien nadal mieć możliwość nadpisania wszelkich przypuszczeń dokonanych przez oprogramowanie. Zbyt wiele razy byłem sfrustrowany, gdy oprogramowanie próbuje być zbyt inteligentne i nie pozwala na poprawienie.
źródło
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; }
źródło
Dlaczego nie
0.1.toLocaleString().replace(/\d/g, '')
źródło
To jest IMO najlepszy sposób działania. Aby poradzić sobie z awariami, dodaj łącze, aby ustawić je ręcznie obok obszaru wyświetlania.
źródło
Korzystając z odpowiedzi innych osób, skompilowałem następujące funkcje użytkowe separatorów dziesiętnych i tysięcy:
var decimalSeparator = function() { return (1.1).toLocaleString().substring(1, 2); }; var thousandSeparator = function() { return (1000).toLocaleString().substring(1, 2); };
Cieszyć się!
źródło
formatToParts
(Safari i IE).(1000).toLocaleString("es-PE") # "1000"
Myślę, że musisz polegać na JavaScript, aby zapewnić ustawienia regionalne.
Ale najwyraźniej JS nie ma bezpośredniego dostępu do tych informacji.
Widzę, że zestaw Dojo Toolkit korzysta z zewnętrznej bazy danych w celu znalezienia informacji o ustawieniach regionalnych, chociaż może na przykład nie uwzględniać zmian ustawień konta.
Innym obejściem, które widzę, jest mały, cichy aplet Java, który odpytuje te informacje z systemu i JavaScript, aby wydobyć je z Javy.
Mogę podać więcej informacji, jeśli nie wiesz, jak to zrobić (jeśli oczywiście chcesz iść tą zawiłą trasą).
[EDYTUJ] Więc zaktualizowałem swoją wiedzę na temat obsługi lokalizacji w Javie ...
W przeciwieństwie do tego, co początkowo sądziłem, nie będziesz mieć bezpośrednio separatora dziesiętnego lub tysięcy znaków, tak jak w przypadku separatora linii lub separatora ścieżki: zamiast Java oferuje interfejsy API do formatowania podanych liczb lub dat.
Jakoś to ma sens: w Europie często umieszcza się symbol waluty po liczbie, w niektórych krajach (Indie?) Obowiązuje bardziej złożona zasada oddzielania cyfr itp.
Inna sprawa: Java poprawnie wyszukuje aktualne ustawienia regionalne z systemu, ale nie pobiera stamtąd informacji (być może z powyższych powodów). Zamiast tego używa własnego zestawu reguł. Więc jeśli masz hiszpańskie ustawienia regionalne, w których zastąpiłeś separator dziesiętny znakiem wykrzyknika, Java go nie użyje (ale może i tak nie jest Twoja aplikacja ...).
Piszę więc aplet udostępniający usługę (funkcje) JavaScriptowi, umożliwiając formatowanie liczb zgodnie z aktualnymi ustawieniami lokalnymi. Możesz go używać jako takiego, używając JavaScript do formatowania liczb w przeglądarce. Możesz też po prostu podać numer próbki i wyodrębnić stamtąd symbole, używając ich lokalnie lub przesyłając je z powrotem do serwera.
Kończę, testuję mój aplet i umieszczam go tam wkrótce.
źródło
OK, mam coś do pokazania, bardziej dowód koncepcji niż gotowy produkt, ale ze względu na brak dokładnych specyfikacji zostawiam to w ten sposób (albo przeprojektuję). Piszę w osobnej wiadomości, bo będzie trochę za długa. Skorzystałem z okazji, aby wypróbować nieco więcej jQuery ...
Kod 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); } }
Przykład strony HTML wykorzystującej powyższy aplet: GetLocaleInfo.html
<!-- Header skipped for brevity --> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.js"></script> <script type="text/javascript"> var applet; $(document).ready(function() { applet = document.getElementById('LocaleInfo'); $('#Results').text(applet.GetLocaleInformation()); }); </script> <script type="text/javascript"> function DoFormatting() { $('table.toFormat').each(function() { var table = $(this); $('td', table).each(function(cellId) { var val = $(this); if (val.is('.number')) { val.text(applet.FormatNumber(val.text())); } else if (val.is('.currency')) { val.text(applet.FormatCurrency(val.text())); } else if (val.is('.percent')) { val.text(applet.FormatPercent(val.text())); } }); }); } </script> </head> <body> <div id="Container"> <p>Page to demonstrate how JavaScript can get locale information from Java</p> <div id="AppletContainer"> <object classid="java:GetLocaleInfo.class" type="application/x-java-applet" codetype="application/java" name="LocaleInfo" id="LocaleInfo" width="0" height="0"> <param name="code" value="GetLocaleInfo"/> <param name="mayscript" value="true"/> <param name="scriptable" value="true"/> <p><!-- Displayed if object isn't supported --> <strong>This browser does not have Java enabled.</strong> <br> <a href="http://java.sun.com/products/plugin/downloads/index.html" title="Download Java plug-in"> Get the latest Java plug-in here </a> (or enable Java support). </p> </object> </div><!-- AppletContainer --> <p> Click on the button to format the table content to the locale rules of the user. </p> <input type="button" name="DoFormatting" id="DoFormatting" value="Format the table" onclick="javascript:DoFormatting()"/> <div id="Results"> </div><!-- Results --> <table class="toFormat"> <caption>Synthetic View</caption> <thead><tr> <th>Name</th><th>Value</th><th>Cost</th><th>Discount</th> </tr></thead> <tbody> <tr><td>Foo</td><td class="number">3.1415926</td><td class="currency">21.36</td><td class="percent">0.196</td></tr> <tr><td>Bar</td><td class="number">159263.14</td><td class="currency">33</td><td class="percent">0.33</td></tr> <tr><td>Baz</td><td class="number">15926</td><td class="currency">12.99</td><td class="percent">0.05</td></tr> <tr><td>Doh</td><td class="number">0.01415926</td><td class="currency">5.1</td><td class="percent">0.1</td></tr> </tbody> </table> </div><!-- Container --> </body> </html>
Testowano w przeglądarce Firefox 3.0, IE 6, Safari 3.1 i Opera 9.50, w systemie Windows XP Pro SP3. Z dwoma pierwszymi działa bez problemu, na Safari mam dziwny błąd po wywołaniu init ():
java.net.MalformedURLException: no protocol: at java.net.URL.<init>(Unknown Source) at java.net.URL.<init>(Unknown Source) at java.net.URL.<init>(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)
ale nadal działa.
Nie mogę sprawić, żeby działało z Operą: aplet ładuje się poprawnie, ponieważ widzę ślad wywołania init () w konsoli Java, nie mam błędów, gdy JavaScript wywołuje funkcje Java (z wyjątkiem sytuacji, gdy dodam i wywołam metodę co ciekawe, pobieranie parametru JSObject), ale funkcje Java nie są wywoływane (dodałem śledzenie wywołań).
Wydaje mi się, że Liveconnect działa w Operze, ale nie wiem jeszcze jak. Zbadam trochę więcej.
[Aktualizacja] Usunąłem odniesienia do nieistniejącego pliku jar (co nie zatrzymuje innych przeglądarek) i otrzymałem ślad wywołań, ale nie aktualizuje to strony.
Mmm, jeśli mam,
alert(applet.GetLocaleInformation());
mam informacje, więc może to być problem z jQuery.źródło
Locale for русский (Россия): country=Россия (RU / RUS), lang=русский (ru / rus), variant= ()
używa przecinka pomimo faktu, że nadpisałem go kropką w ustawieniach systemu Windows.Nawet jeśli nie wiedział, co to locale „GUI aplikacji” pracuje pod, trzeba jeszcze, aby dowiedzieć się, jak to jest coraz bieżące locale, i jak to jest określenie separator dziesiętny.
Nie wiem, jak to się robi na Macu, ale aplikacje Windows mają sprawdzać preferencje użytkownika ustawione w Panelu sterowania. Jest całkiem możliwe, że ta tajemnicza aplikacja ignoruje te ustawienia i używa zamiast tego własnej wewnętrznej konfiguracji.
A może raczej wybierają aktualne lokalizacje i wnioskują o resztę, zamiast mówić.
Nawet wtedy, w języku angielskim, liczby podaje się w grupach po 3 cyfry, oddzielając je przecinkami. to znaczy:
O ile numer nie był liczbą całkowitą zawierającą numer telefonu :
O ile oczywiście liczba nie była liczbą całkowitą zawierającą numer konta :
W takim przypadku wrócisz do zakodowanej na stałe zastąpionej logiki.
Edycja: Usunięto przykład waluty, ponieważ waluta ma własne reguły formatowania.
źródło
Podobne do innych odpowiedzi, ale skompresowane jako stała :
const decimal=.1.toLocaleString().substr(1,1); //returns "." in Canada
Aby uzyskać separator tysięcy :
const thousands=1234..toLocaleString().substr(1,1); //returns "," in Canada
Po prostu umieść kod na górze swojego JS, a następnie wywołaj zgodnie z wymaganiami, aby zwrócić symbol.
Na przykład (gdzie mieszkam), aby usunąć przecinki z
"1,234,567"
:console.log( "1,234,567".replaceAll(thousands,"") ); //prints "1234567" to console.
źródło
Nie, nie możesz. Ten GUI sprawdza niektóre ustawienia użytkownika lub komputera. Po pierwsze, prawdopodobnie nie wiesz, jakich ustawień szuka ten interfejs użytkownika. Po drugie, z aplikacją internetową prawdopodobnie nie będziesz w stanie sprawdzić tych ustawień (strona klienta -> Javacsript).
źródło
Inne możliwe rozwiązanie: możesz użyć czegoś takiego jak GeoIP (przykład w PHP), aby określić lokalizację użytkownika i zdecydować na podstawie tych informacji.
źródło