Revision 128232cd
Added by Marc Dequènes over 15 years ago
- ID 128232cd678d9c9613296cf548fefbacbd476806
lib/http_headers.rb | ||
---|---|---|
require 'locale'
|
||
|
||
module HTTPHeaders
|
||
# RFC2616 Accept-Language field
|
||
# (also used in RFC2798 'preferredLanguage' LDAP attribute type)
|
||
class AcceptLanguage
|
||
LANG_RANGE_Q_PATTERN="([a-z]{1,8}(-[a-z]{1,8})*(;q=)|\*)"
|
||
ACCEPT_LANG_PATTERN="#{LANG_RANGE_Q_PATTERN}( *, *#{LANG_RANGE_Q_PATTERN})*"
|
||
|
||
attr_reader :sorted_language_list
|
||
|
||
private :new
|
||
|
||
def initialize(sorted_language_list)
|
||
# if no preference list, then assume that all languages are equally acceptable
|
||
@sorted_language_list = sorted_language_list.empty? ? ["*"] : sorted_language_list
|
||
end
|
||
|
||
def self.parse(accept_language_list)
|
||
return nil unless accept_language_list =~ Regexp.new(ACCEPT_LANG_PATTERN, Regexp::EXTENDED | Regexp::IGNORECASE)
|
||
|
||
list = accept_language_list.split(',').collect do |lang_range_q|
|
||
lang_range, quality = lang_range_q.split(';')
|
||
quality ||= 1
|
||
LanguageRange.new(lang_range, quality)
|
||
end
|
||
|
||
new(list.sort)
|
||
end
|
||
|
||
def reduce(available_language_list)
|
||
tag_list = available_language_list.collect do |tag|
|
||
l_tag = Locale::Object.new(tag)
|
||
|
||
match = []
|
||
@sorted_language_list.each do |lr|
|
||
match << lr if lr.range == "*" or
|
||
lr.range == l_tag.to_iso3066 or
|
||
(lr.range + "-" == l_tag.to_iso3066[0, lr.range.size + 1])
|
||
end
|
||
match.sort_by {|lr| lr.range.size }
|
||
|
||
quality = match.empty? ? 0 : match.last.quality
|
||
|
||
LanguageRange.new(l_tag, quality)
|
||
end
|
||
|
||
acceptable_tag_list = tag_list.select {|lt| lr.quality != 0 }
|
||
acceptable_tag_list.sort
|
||
end
|
||
end
|
||
|
||
class LanguageRange
|
||
include Sortable
|
||
|
||
attr_reader :quality
|
||
|
||
def initialize(lang_range, quality)
|
||
@l_lang_range = (lang_range.is_a? Locale::Object) ? lang_range : Locale::Object.new(lang_range)
|
||
@quality = quality.to_f
|
||
end
|
||
|
||
def range
|
||
@l_lang_range.to_iso3066
|
||
end
|
||
|
||
def <=>(lr)
|
||
r = self.quality <=> lr.quality
|
||
# if quality is equal, then prefer the most specific language range
|
||
if r == 0
|
||
self.range.size <=> lr.range.size
|
||
else
|
||
r
|
||
end
|
||
end
|
||
end
|
||
end
|
lib/language.rb | ||
---|---|---|
require 'locale'
|
||
|
||
module HTTPHeaders
|
||
# RFC2616 Accept-Language field
|
||
# (also used in RFC2798 'preferredLanguage' LDAP attribute type)
|
||
class AcceptLanguage
|
||
LANG_RANGE_Q_PATTERN="([a-z]{1,8}(-[a-z]{1,8})*(;q=)|\*)"
|
||
ACCEPT_LANG_PATTERN="#{LANG_RANGE_Q_PATTERN}( *, *#{LANG_RANGE_Q_PATTERN})*"
|
||
|
||
attr_reader :sorted_language_list
|
||
|
||
private :new
|
||
|
||
def initialize(sorted_language_list)
|
||
# if no preference list, then assume that all languages are equally acceptable
|
||
@sorted_language_list = sorted_language_list.empty? ? ["*"] : sorted_language_list
|
||
end
|
||
|
||
def self.parse(accept_language_list)
|
||
return nil unless accept_language_list =~ Regexp.new(ACCEPT_LANG_PATTERN, Regexp::EXTENDED | Regexp::IGNORECASE)
|
||
|
||
list = accept_language_list.split(',').collect do |lang_range_q|
|
||
lang_range, quality = lang_range_q.split(';')
|
||
quality ||= 1
|
||
LanguageRange.new(lang_range, quality)
|
||
end
|
||
|
||
new(list.sort)
|
||
end
|
||
|
||
def reduce(available_language_list)
|
||
tag_list = available_language_list.collect do |tag|
|
||
l_tag = Locale::Object.new(tag)
|
||
|
||
match = []
|
||
@sorted_language_list.each do |lr|
|
||
match << lr if lr.range == "*" or
|
||
lr.range == l_tag.to_iso3066 or
|
||
(lr.range + "-" == l_tag.to_iso3066[0, lr.range.size + 1])
|
||
end
|
||
match.sort_by {|lr| lr.range.size }
|
||
|
||
quality = match.empty? ? 0 : match.last.quality
|
||
|
||
LanguageRange.new(l_tag, quality)
|
||
end
|
||
|
||
acceptable_tag_list = tag_list.select {|lt| lr.quality != 0 }
|
||
acceptable_tag_list.sort
|
||
end
|
||
end
|
||
|
||
class LanguageRange
|
||
include Sortable
|
||
|
||
attr_reader :quality
|
||
|
||
def initialize(lang_range, quality)
|
||
@l_lang_range = (lang_range.is_a? Locale::Object) ? lang_range : Locale::Object.new(lang_range)
|
||
@quality = quality.to_f
|
||
end
|
||
|
||
def range
|
||
@l_lang_range.to_iso3066
|
||
end
|
||
|
||
def <=>(lr)
|
||
r = self.quality <=> lr.quality
|
||
# if quality is equal, then prefer the most specific language range
|
||
if r == 0
|
||
self.range.size <=> lr.range.size
|
||
else
|
||
r
|
||
end
|
||
end
|
||
end
|
||
end
|
Also available in: Unified diff
[evol] RFC2616 Accept-Language field support #3 (forgot to rename file)