Class: Utopia::Localization

Inherits:
Object
  • Object
show all
Defined in:
lib/utopia/localization.rb

Overview

If you request a URL which has localized content, a localized redirect would be returned based on the content requested.

Constant Summary collapse

RESOURCE_NOT_FOUND =
[400, {}, []].freeze
HTTP_ACCEPT_LANGUAGE =
'HTTP_ACCEPT_LANGUAGE'.freeze
LOCALIZATION_KEY =
'utopia.localization'.freeze
CURRENT_LOCALE_KEY =
'utopia.localization.current_locale'.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, options = {}) ⇒ Localization

Returns a new instance of Localization.



52
53
54
55
56
57
58
59
# File 'lib/utopia/localization.rb', line 52

def initialize(app, options = {})
	@app = app

	@default_locale = options[:default_locale] || "en"
	@all_locales = options[:locales] || ["en"]
	
	@nonlocalized = options.fetch(:nonlocalized, [])
end

Instance Attribute Details

#all_localesObject (readonly)

Returns the value of attribute all_locales.



61
62
63
# File 'lib/utopia/localization.rb', line 61

def all_locales
  @all_locales
end

#default_localeObject (readonly)

Returns the value of attribute default_locale.



62
63
64
# File 'lib/utopia/localization.rb', line 62

def default_locale
  @default_locale
end

Instance Method Details

#browser_preferred_locales(env) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/utopia/localization.rb', line 84

def browser_preferred_locales(env)
	accept_languages = env[HTTP_ACCEPT_LANGUAGE]
	
	# No user prefered languages:
	return [] unless accept_languages

	languages = accept_languages.split(',').map { |language|
		language.split(';q=').tap{|x| x[1] = (x[1] || 1.0).to_f}
	}.sort{|a, b| b[1] <=> a[1]}.collect(&:first)
	
	# Returns languages based on the order of the first argument
	return languages & @all_locales
end

#call(env) ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/utopia/localization.rb', line 124

def call(env)
	return @app.call(env) if nonlocalized?(env)
	
	env[LOCALIZATION_KEY] = self
	
	response = nil
	
	# We have a non-localized request, but there might be a localized resource. We return the best localization possible:
	preferred_locales(env).each do |locale|
		env[CURRENT_LOCALE_KEY] = locale
		
		response = @app.call(env)
		
		break unless response[0] >= 400
	end
	
	return vary(env, response)
end

#nonlocalized?(env) ⇒ Boolean

Returns:

  • (Boolean)


98
99
100
101
102
# File 'lib/utopia/localization.rb', line 98

def nonlocalized?(env)
	path_info = env['PATH_INFO']
	
	@nonlocalized.any? { |pattern| path_info[pattern] != nil }
end

#preferred_locales(env) ⇒ Object



64
65
66
# File 'lib/utopia/localization.rb', line 64

def preferred_locales(env)
	request_preferred_locales(env) | browser_preferred_locales(env) | [@default_locale, nil]
end

#request_preferred_locales(env) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/utopia/localization.rb', line 68

def request_preferred_locales(env)
	path = Path[env['PATH_INFO']]
	
	if all_locales.include? path.first
		request_locale = path.first
		
		# Remove the localization prefix.
		path.delete_at(0)
		env['PATH_INFO'] = path.to_s
		
		return [request_locale]
	else
		return []
	end
end

#vary(env, response) ⇒ Object

Set the Vary: header on the response to indicate that this response should include the header in the cache key.



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/utopia/localization.rb', line 105

def vary(env, response)
	headers = response[1]
	
	# This response was based on the Accept-Language header:
	if headers['Vary']
		headers['Vary'] += ',Accept-Language'
	else
		headers['Vary'] = 'Accept-Language'
	end
	
	# Althought this header is generally not supported, we supply it anyway as it is useful for debugging:
	if locale = env[CURRENT_LOCALE_KEY]
		# Set the Content-Location to point to the localized URI as requested:
		headers['Content-Location'] = "/#{locale}" + env['PATH_INFO']
	end
	
	return response
end