phtrivier

phtrivier

Is there an Hex package to parse "Accept-Language" header?

Is there an hex library suitable to parse an “Accept-Language” header, including the “edge-cases” with “quality-value” syntax ?

Examples (see MDN )

Accept-Language: en
Accept-Language: en-US
Accept-Language: *

// Multiple types, weighted with the quality value syntax:
Accept-Language: fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5

The RFC would be https://tools.ietf.org/html/rfc7231#section-5.3.5

I suppose splitting the string and handling edge cases myself would not be terribly complicated, just wondering if someone had already done this :smiley:

Most Liked

kuroda

kuroda

As @g-andrade said, we can use cowlib.

accept_language = "ja,en-US;q=0.9,en;q=0.8,zh-CN;q=0.7,zh;q=0.6"

:cow_http_hd.parse_accept_language(accept_language)

This code returns [{"ja", 1000}, {"en-us", 900}, {"en", 800}, {"zh-cn", 700}, {"zh", 600}].

Note that the cowlib converts all letters in the country code to lowercase.

kip

kip

ex_cldr Core Team

I fixed the documentation link issue: one of the recent versions of ex_doc lowercases all the doc files but I had “README” in the docs section of mix.exs. Thanks for the heads-up.

Using your data there is an example below. Note that list will be returned in sorted order so hd will return you the highest priority in the list.

See:

  • Cldr.AcceptLanguage.parse/1
  • Cldr.AcceptLanguage.parse!/1
  • Cldr.AcceptLanguage.best_match/1
  • Cldr.AcceptLanguage.errors/1

If you have ex_cldr locales configured then it will populate the :cldr_locale_name with the nearest matching configured locale. You’ll notice that only “en” is configured in this instance.

The matching algorithm implements all of the CLDR aliases and does sub tag replacement. It also parse, almost completely, the full definition of a language tag as defined by RFC5646 (ask me if you want to know the exception :slight_smile:)

iex> Cldr.known_locale_names
["af", "bs", "en", "en-GB", "he", "it", "pl", "root", "ru", "th"]

# Return the locale that most nearly matches the configured Cldr locales above.
# Since "fr", "fr-CH" and "de" are not configured it returns "en"
iex> Cldr.AcceptLanguage.best_match "fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5"
{:ok,
 %Cldr.LanguageTag{
   canonical_locale_name: "en-Latn-US",
   cldr_locale_name: "en",
   extensions: %{},
   gettext_locale_name: "en",
   language: "en",
   locale: %{},
   private_use: [],
   rbnf_locale_name: "en",
   requested_locale_name: "en",
   script: "Latn",
   territory: "US",
   transform: %{},
   variant: nil
 }}

# Returns the parsed list of locals in "q" descending order with
# any parse errors appended to the end of the list.
iex> Cldr.AcceptLanguage.parse "fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5"
{:ok,
 [
   {1.0,
    %Cldr.LanguageTag{
      canonical_locale_name: "fr-Latn-CH",
      cldr_locale_name: nil,
      extensions: %{},
      gettext_locale_name: nil,
      language: "fr",
      locale: %{},
      private_use: [],
      rbnf_locale_name: nil,
      requested_locale_name: "fr-CH",
      script: "Latn",
      territory: "CH",
      transform: %{},
      variant: nil
    }},
   {0.9,
    %Cldr.LanguageTag{
      canonical_locale_name: "fr-Latn-FR",
      cldr_locale_name: nil,
      extensions: %{},
      gettext_locale_name: nil,
      language: "fr",
      locale: %{},
      private_use: [],
      rbnf_locale_name: nil,
      requested_locale_name: "fr",
      script: "Latn",
      territory: "FR",
      transform: %{},
      variant: nil
    }},
   {0.8,
    %Cldr.LanguageTag{
      canonical_locale_name: "en-Latn-US",
      cldr_locale_name: "en",
      extensions: %{},
      gettext_locale_name: "en",
      language: "en",
      locale: %{},
      private_use: [],
      rbnf_locale_name: "en",
      requested_locale_name: "en",
      script: "Latn",
      territory: "US",
      transform: %{},
      variant: nil
    }},
   {0.7,
    %Cldr.LanguageTag{
      canonical_locale_name: "de-Latn-DE",
      cldr_locale_name: nil,
      extensions: %{},
      gettext_locale_name: nil,
      language: "de",
      locale: %{},
      private_use: [],
      rbnf_locale_name: nil,
      requested_locale_name: "de",
      script: "Latn",
      territory: "DE",
      transform: %{},
      variant: nil
    }}
 ]}
LostKobrakai

LostKobrakai

g-andrade

g-andrade

I believe cowlib can also handle it (among other headers.)

Where Next?

Popular in Questions Top

dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
pgiesin
This should be a simple problem but I just can’t seem to figure it out. I have a standalone Elixir app that won’t find the database. Dep...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
Kagamiiiii
Student & New to elixir. Nice language. I want to convert a english character, e.g. “a”, which is stored in a variable, to it’s asci...
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
hpopp
To simplify some tasks at work, I wrote and published this package yesterday. It’s a simple macro that enables Access behaviour on struct...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> someth...
New

Other popular topics Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
AstonJ
You’re a programmer, so you don’t need spoon feeding with the conventional drivel about “this is an integer.” No. You need to know what’s...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New

We're in Beta

About us Mission Statement