Class: Rack::I18nBestLangs
- Inherits:
-
Object
- Object
- Rack::I18nBestLangs
- Defined in:
- lib/rack/i18n_best_langs.rb
Constant Summary collapse
- RACK_VARIABLE =
'rack.i18n_best_langs'.freeze
- DEFAULT_WEIGHTS =
{ :header => 1, :aliases_path => 2, :path => 3, :cookie => 4, }.freeze
- HEADER_FORMAT =
self.accept_language_format.freeze
Class Method Summary collapse
Instance Method Summary collapse
- #add_score_for_accept_language_header(accept_language_header, langs) ⇒ Object
- #add_score_for_aliases_path(path, langs) ⇒ Object
- #add_score_for_cookie(cookie, langs) ⇒ Object
- #add_score_for_path(path, langs) ⇒ Object
- #call(env) ⇒ Object
- #extract_language_cookie(env) ⇒ Object
- #extract_language_header(env) ⇒ Object
- #find_best_languages(env) ⇒ Object
-
#initialize(app, avail_languages, opts = {}) ⇒ I18nBestLangs
constructor
Create a new I18nBestLangs middleware component.
- #languages_in_accept_language(accept_language_header) ⇒ Object
- #regex_for_languages_in_path ⇒ Object
- #remove_language_from_path(path) ⇒ Object
- #valid_language_header(accept_language_header) ⇒ Object
Constructor Details
#initialize(app, avail_languages, opts = {}) ⇒ I18nBestLangs
Create a new I18nBestLangs middleware component.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/rack/i18n_best_langs.rb', line 35 def initialize(app, avail_languages, opts = {}) @app = app score_base = avail_languages.length weights = opts[:weights] || DEFAULT_WEIGHTS @score_for_header = score_base * (10 ** weights[:header]) @score_for_aliases_path = score_base * (10 ** weights[:aliases_path]) @score_for_path = score_base * (10 ** weights[:path]) @score_for_cookie = score_base * (10 ** weights[:cookie]) @avail_languages = {} avail_languages.each_with_index do |lang, i| code = LanguageTag.new(lang).freeze score = score_base - i @avail_languages[code] = score end @avail_languages.freeze @language_path_regex = regex_for_languages_in_path.freeze @path_mapping_fn = opts[:path_mapping_fn] end |
Class Method Details
.accept_language_format ⇒ Object
206 207 208 209 210 211 |
# File 'lib/rack/i18n_best_langs.rb', line 206 def self.accept_language_format lang = '[-_a-zA-Z]+' qvalue = '(; ?q=[01]+(\.[0-9]{1,3})?)' return Regexp.new("\\A#{lang}#{qvalue}?(, ?#{lang}#{qvalue}?)*\\Z") end |
Instance Method Details
#add_score_for_accept_language_header(accept_language_header, langs) ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/rack/i18n_best_langs.rb', line 123 def add_score_for_accept_language_header(accept_language_header, langs) if accept_language_header.nil? || !valid_language_header(accept_language_header) return end header_langs = languages_in_accept_language(accept_language_header) header_langs.each do |lang, q| if !langs.include?(lang) next end langs[lang] += @score_for_header * q end end |
#add_score_for_aliases_path(path, langs) ⇒ Object
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/rack/i18n_best_langs.rb', line 156 def add_score_for_aliases_path(path, langs) if !@path_mapping_fn.respond_to?(:path_analysis) return end ph, translation, aliases_langs = @path_mapping_fn.path_analysis(path) aliases_langs.map! { |tag| LanguageTag.parse(tag) } lang_uses = aliases_langs.inject(Hash.new(0)) {|freq, lang| freq[lang] += 1; freq } lang_uses.sort_by { |lang, freq| -freq }.each do |lang, freq| if !langs.include?(lang) next end langs[lang] += @score_for_aliases_path * freq end end |
#add_score_for_cookie(cookie, langs) ⇒ Object
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/rack/i18n_best_langs.rb', line 139 def (, langs) if .nil? return end = .split(',').map { |tag| LanguageTag.parse(tag) } .reverse.each_with_index do |lang, idx| if !langs.include?(lang) next end importance = idx + 1 langs[lang] += @score_for_cookie * importance end end |
#add_score_for_path(path, langs) ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/rack/i18n_best_langs.rb', line 111 def add_score_for_path(path, langs) path_match = path.match(@language_path_regex) path_include_language = !path_match.nil? if !path_include_language return end lang_code = LanguageTag.new(path_match[1]) langs[lang_code] += @score_for_path end |
#call(env) ⇒ Object
60 61 62 63 64 65 66 67 |
# File 'lib/rack/i18n_best_langs.rb', line 60 def call(env) lang_info = find_best_languages(env) env[RACK_VARIABLE] = lang_info[:languages] env['PATH_INFO'] = lang_info[:path_info] return @app.call(env) end |
#extract_language_cookie(env) ⇒ Object
103 104 105 |
# File 'lib/rack/i18n_best_langs.rb', line 103 def (env) return Rack::Request.new(env).[RACK_VARIABLE] end |
#extract_language_header(env) ⇒ Object
92 93 94 95 96 97 98 99 100 101 |
# File 'lib/rack/i18n_best_langs.rb', line 92 def extract_language_header(env) header = env['HTTP_ACCEPT_LANGUAGE'] if !(header =~ HEADER_FORMAT) env["rack.errors"].puts("Warning: malformed Accept-Language header") return nil end return header end |
#find_best_languages(env) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/rack/i18n_best_langs.rb', line 69 def find_best_languages(env) path = env['PATH_INFO'] accept_language_header = extract_language_header(env) = (env) clean_path_info = remove_language_from_path(path) langs = @avail_languages.dup add_score_for_path(path, langs) add_score_for_accept_language_header(accept_language_header, langs) (, langs) add_score_for_aliases_path(path, langs) sorted_langs = langs.to_a.sort_by { |lang_info| -(lang_info[1]) }.map(&:first) info = { :languages => sorted_langs, :path_info => clean_path_info, } return info end |
#languages_in_accept_language(accept_language_header) ⇒ Object
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/rack/i18n_best_langs.rb', line 178 def languages_in_accept_language(accept_language_header) raw_langs = accept_language_header.split(',') langs = raw_langs.map { |l| l.sub('q=', '')}. map { |l| l.split(';') } langs.each_with_index do |l, i| l[0] = LanguageTag.parse(l[0]) l[1] = (l[1] || 1).to_f sorting_epsilon = (langs.size - i).to_f / 100 l[1] += sorting_epsilon # keep the original order when sorting end return langs end |
#regex_for_languages_in_path ⇒ Object
195 196 197 198 199 200 201 202 203 |
# File 'lib/rack/i18n_best_langs.rb', line 195 def regex_for_languages_in_path all_languages = @avail_languages.keys.map(&:alpha3) preamble = "/" body = "(" + all_languages.join("|") + ")" trail = "/?$" return Regexp.new(preamble + body + trail) end |
#remove_language_from_path(path) ⇒ Object
107 108 109 |
# File 'lib/rack/i18n_best_langs.rb', line 107 def remove_language_from_path(path) return path.sub(@language_path_regex, '') end |
#valid_language_header(accept_language_header) ⇒ Object
174 175 176 |
# File 'lib/rack/i18n_best_langs.rb', line 174 def valid_language_header(accept_language_header) return true # FIXME: check with regex end |