Analizza sia en_US che en-US come locale in Java

2

Sto scrivendo un'API (usando Java) che accetta le impostazioni locali come parametro. Vogliamo che i clienti siano in grado di specificare "en-US" o "en_US" in quanto sembrano entrambi ampiamente utilizzati in tutte le lingue.

Ho seguito questi link

  1. Come ottenere le impostazioni locali dalla rappresentazione delle stringhe in Java
  2. en_US o en-US, quale dovrebbe tu usi
  3. documentazione locale Java

Documentazione Java (fonte 3 dall'alto) afferma "I valori delle varianti ben formati hanno il formato SUBTAG (('_' | '-') SUBTAG) * dove SUBTAG = [0-9] [0-9a-zA- Z] {3} | [0-9a-zA-Z] {5,8}. (Nota: BCP 47 usa solo il trattino ('-') come delimitatore, questo è più indulgente). "

Il modo in cui ho capito che sia "_" e "-" sono supportati, ma il loro codice supporta solo "-". vedi sotto il mio test di unità di prova che fallisce, ma passa se uso "en-US".

@Test
public void testLocale() {
    Locale locale = Locale.forLanguageTag("en_US");
    assertThat(locale.getLanguage(), equalTo("en"));
}

Ci sono modi per analizzare un locale da entrambe le forme di stringa "en_US" e "en-US"? Qual è l'approccio consigliato qui?

    
posta srini 22.07.2016 - 04:24
fonte

2 risposte

2

Sostituisci ogni occorrenza di "_" di "-" nella stringa locale quando ricevi il parametro e lascia che la logica si aspetti solo "-" .

    
risposta data 22.07.2016 - 20:36
fonte
9

Invece di rimpiazzare senza capire vorrei spiegare perché sembrano esserci due forme, una sottolineata e un'altra trattata, e perché ci si dovrebbe preoccupare.

tl; dr non è semplice come sostituzione di un singolo carattere.

1. specifiche

Ci sono diverse specifiche in gioco qui:

  • ICU : I nternazionale C omponents per U nicode che ha una sezione su come codificare / rappresentare locali (lingua, paese, script, variante, ecc.), questo progetto è usato principalmente in lingue native come C. E non dovrebbe essere mescolato con impostazioni locali in un sistema POSIX.

  • Unicode CLDR : che offre un'interessante pagina semplice su equivalenza con tag lingua . Questa rappresentazione consente sia trattini che underscore, mentre preferisce il trattino. Anche questo è diverso da ICU.

  • (BCP 47 / RFC 4646 ) ⇒ RFC 5646 riguarda il tag del linguaggio utilizzato nelle intestazioni HTTP ( RFC 3282 ) soprattutto in Content-Language e in Accept-Language (intervalli di lingue).

Quindi lo standard nel web è di utilizzare i tag di lingua in alcune intestazioni. In questo modo

  • Se l'applicazione server si basa su intestazioni HTTP standard, dovrebbe gestire i tag di lingua (intervallo di linguaggio più specifico per Accept-Language ).

  • Se l'applicazione server utilizza un'intestazione personalizzata come Company-MyApp-Other-Language , nessun problema, è personalizzato per questo ecosistema.

  • Se l'applicazione client utilizza intestazioni HTTP standard ma utilizza un formato non valido, allora l'app server dovrebbe provare a gestirli.

2. alcuni dettagli di implementazione

La cosa bella di PHP Locale è che gestisce il formato ICU e i tag della lingua.

Tuttavia per Java la storia è un po 'più complicata, dal momento che Locale classe è piuttosto vecchia (dal JDK 1.1 circa 1997) e non è stata in grado di analizzare o formattare ( toString ) in nessuno degli standard sopra citati, ha usato il carattere di sottolineatura come separatore ma non è conforme all'ICU. In JDK 1.7 circa 2011 sono stati aggiunti forLanguageTag / toLanguageTag per supportare lo standard BCP 47 / RFC 4646; i vecchi metodi mantenevano il loro comportamento precedente per compatibilità con le versioni precedenti. A questa data (marzo 2018) il formato locale ICU / CLDR non è supportato dalle impostazioni internazionali di JDK.

In effetti, l'approccio ingenuo, che funziona nella maggior parte delle situazioni (99,999%) è quello di sostituire i caratteri di sottolineatura con trattini. Alcuni casi rari possono comparire quando la stringa contiene solo un'estensione.

Tuttavia questo non funziona per ogni rappresentazione ICU, specialmente quando ci sono parole chiave ICU come @currency=... , quelle non possono essere convertite tramite una singola sostituzione di caratteri.

  • sr_Latn_RS_REVISED@currency=USD
  • en_IE@currency=IEP

Inoltre, questo non funzionerà con i client java che usano il toString di Java ambiente, questo è più probabile che causi problemi in alcuni paesi in cui lo script è una parte importante per le impostazioni internazionali, ad es. per la Serbia:

  • Locale.forLanguageTag("sr-Latn-RS").toString()sr_RS_#Latn , questo legacy toString non può essere interpretato come un tag di lingua valido, infatti il parser respinge completamente lo script.

Quindi gestire ogni possibile cattivo comportamento in un'intestazione standard è complicato, il migliore sarebbe imporre il rispetto del tag della lingua RFC, che il browser rispetta. Se non è possibile, è meglio identificare quale applicazione è responsabile di questo comportamento scorretto e qual è il formato utilizzato. Ciò eviterebbe di gestire ogni possibile formato.

3. post scriptum

Inoltre, la parte javadoc citata nella domanda si applica solo alla parte variante di una locale, non alla lingua e al paese

Well-formed variant values have the form SUBTAG (('_'|'-') SUBTAG)* where SUBTAG = [0-9][0-9a-zA-Z]{3} | [0-9a-zA-Z]{5,8}. (Note: BCP 47 only uses hyphen ('-') as a delimiter, this is more lenient).

    
risposta data 15.03.2018 - 12:58
fonte

Leggi altre domande sui tag