Class: Utopia::Localization::Middleware
- Inherits:
-
Protocol::HTTP::Middleware
- Object
- Protocol::HTTP::Middleware
- Utopia::Localization::Middleware
- Defined in:
- lib/utopia/localization/middleware.rb
Overview
Computes localization preferences and rewrites locale-prefixed paths.
Instance Attribute Summary collapse
-
#all_locales ⇒ Object
readonly
Returns the value of attribute all_locales.
-
#default_locale ⇒ Object
readonly
Returns the value of attribute default_locale.
Instance Method Summary collapse
-
#browser_preferred_locales(request) ⇒ Object
Parse the locales preferred by the browser.
-
#call(request) ⇒ Object
Attach localization preferences and invoke the application once.
-
#extract_path_locale(request) ⇒ Object
Extract a locale prefix from the request path.
-
#freeze ⇒ Object
Freeze this object and its internal state.
-
#host_preferred_locales(request) ⇒ Object
Infer preferred locales from the request authority.
-
#initialize(app, locales:, default_locale: nil, default_locales: nil, hosts: {}, ignore: []) ⇒ Middleware
constructor
A new instance of Middleware.
-
#localized?(request) ⇒ Boolean
Check whether the request path includes a locale.
-
#preferred_locales(request, path_locale = nil) ⇒ Object
Compute the preferred locales for a request.
-
#vary(response) ⇒ Object
Mark the response as varying by language.
Constructor Details
#initialize(app, locales:, default_locale: nil, default_locales: nil, hosts: {}, ignore: []) ⇒ Middleware
Returns a new instance of Middleware.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/utopia/localization/middleware.rb', line 24 def initialize(app, locales:, default_locale: nil, default_locales: nil, hosts: {}, ignore: []) super(app) @all_locales = Locales.new(locales) # Locales here are represented as an array of strings, e.g. ['en', 'ja', 'cn', 'de'] and are used in order if no locale is specified by the user. unless @default_locales = default_locales if default_locale @default_locales = [default_locale, nil] else # We append nil, i.e. no localization. @default_locales = @all_locales.names + [nil] end end @default_locale = default_locale || @default_locales.first unless @default_locales.include? @default_locale @default_locales.unshift(@default_locale) end # Select a localization based on a request host name: @hosts = hosts @ignore = ignore end |
Instance Attribute Details
#all_locales ⇒ Object (readonly)
Returns the value of attribute all_locales.
65 66 67 |
# File 'lib/utopia/localization/middleware.rb', line 65 def all_locales @all_locales end |
#default_locale ⇒ Object (readonly)
Returns the value of attribute default_locale.
66 67 68 |
# File 'lib/utopia/localization/middleware.rb', line 66 def default_locale @default_locale end |
Instance Method Details
#browser_preferred_locales(request) ⇒ Object
Parse the locales preferred by the browser.
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/utopia/localization/middleware.rb', line 147 def browser_preferred_locales(request) accept_languages = request.headers["accept-language"] # No user prefered languages: return [] unless accept_languages # Extract the ordered list of languages: languages = accept_languages.preferred_languages # Returns available languages based on the order languages: return @all_locales.match(languages) rescue Protocol::HTTP::Header::AcceptLanguage::ParseError # If we fail to parse the browser Accept-Language header, we ignore it (silently). return [] end |
#call(request) ⇒ Object
Attach localization preferences and invoke the application once.
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/utopia/localization/middleware.rb', line 190 def call(request) # Pass the request through if it shouldn't be localized: return @delegate.call(request) unless localized?(request) request, path_locale = extract_path_locale(request) locales = preferred_locales(request, path_locale) request.localization = Preferences.new( all_locales: @all_locales.names, preferred_locales: locales, default_locale: @default_locale, ) return vary(@delegate.call(request)) end |
#extract_path_locale(request) ⇒ Object
Extract a locale prefix from the request path.
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/utopia/localization/middleware.rb', line 113 def extract_path_locale(request) path = request.url.path # Localization prefixes only apply to absolute application paths: unless path.absolute? return request, nil end if segment = path.segments[1] # Decode only the component which may contain the locale: component = Protocol::URL::Encoding::System.unescape(segment) if request_locale = @all_locales.patterns[component] # Remove the locale while preserving all other encoded segments: segments = path.segments.dup segments.delete_at(1) # Preserve the absolute root when the locale was the only component: if segments == [""] segments << "" end path = Protocol::URL::Path.new(nil, segments) return request.with(path: path), request_locale end end return request, nil end |
#freeze ⇒ Object
Freeze this object and its internal state.
53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/utopia/localization/middleware.rb', line 53 def freeze return self if frozen? @all_locales.freeze @default_locales.freeze @default_locale.freeze @hosts.freeze @ignore.freeze super end |
#host_preferred_locales(request) ⇒ Object
Infer preferred locales from the request authority.
99 100 101 102 103 104 105 106 107 108 |
# File 'lib/utopia/localization/middleware.rb', line 99 def host_preferred_locales(request) = request..to_s # Yield all hosts which match the incoming authority: @hosts.each do |pattern, locale| if [pattern] yield locale end end end |
#localized?(request) ⇒ Boolean
Check whether the request path includes a locale.
166 167 168 169 170 171 172 |
# File 'lib/utopia/localization/middleware.rb', line 166 def localized?(request) # Ignore requests which match the ignored paths: path = request.url.path.encoded return false if @ignore.any?{|pattern| path[pattern] != nil} return true end |
#preferred_locales(request, path_locale = nil) ⇒ Object
Compute the preferred locales for a request.
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/utopia/localization/middleware.rb', line 72 def preferred_locales(request, path_locale = nil) # Keep track of what locales have been tried: locales = Set.new if path_locale locales.add(path_locale) end host_preferred_locales(request) do |locale| locales.add(locale) end browser_preferred_locales(request).each do |locale| locales.add(locale) end @default_locales.each do |locale| locales.add(locale) end return locales.to_a end |
#vary(response) ⇒ Object
Mark the response as varying by language.
177 178 179 180 181 182 183 184 185 |
# File 'lib/utopia/localization/middleware.rb', line 177 def vary(response) response = Response.wrap(response) headers = response.headers # This response was based on the Accept-Language header: headers.add("vary", "Accept-Language") return response end |