Skip to content

Commit

Permalink
Add localized templates
Browse files Browse the repository at this point in the history
  # Default locale
  app/views/messages/index.html.erb

  # I18n.locale is set to :da (Danish)
  app/views/messages/index.da.html.erb
  • Loading branch information
josh committed Jan 26, 2009
1 parent 5c062bf commit a98cd7c
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 15 deletions.
6 changes: 5 additions & 1 deletion actionpack/lib/action_view/paths.rb
Expand Up @@ -37,7 +37,11 @@ def find_template(original_template_path, format = nil)
template_path = original_template_path.sub(/^\//, '')

each do |load_path|
if format && (template = load_path["#{template_path}.#{format}"])
if format && (template = load_path["#{template_path}.#{I18n.locale}.#{format}"])
return template
elsif format && (template = load_path["#{template_path}.#{format}"])
return template
elsif template = load_path["#{template_path}.#{I18n.locale}"]
return template
elsif template = load_path[template_path]
return template
Expand Down
56 changes: 42 additions & 14 deletions actionpack/lib/action_view/template.rb
Expand Up @@ -93,13 +93,14 @@ def self.exempt_from_layout(*extensions)
@@exempt_from_layout.merge(regexps)
end

attr_accessor :filename, :load_path, :base_path, :name, :format, :extension
attr_accessor :filename, :load_path, :base_path
attr_accessor :locale, :name, :format, :extension
delegate :to_s, :to => :path

def initialize(template_path, load_paths = [])
template_path = template_path.dup
@load_path, @filename = find_full_path(template_path, load_paths)
@base_path, @name, @format, @extension = split(template_path)
@base_path, @name, @locale, @format, @extension = split(template_path)
@base_path.to_s.gsub!(/\/$/, '') # Push to split method

# Extend with partial super powers
Expand Down Expand Up @@ -137,17 +138,17 @@ def mime_type
memoize :mime_type

def path
[base_path, [name, format, extension].compact.join('.')].compact.join('/')
[base_path, [name, locale, format, extension].compact.join('.')].compact.join('/')
end
memoize :path

def path_without_extension
[base_path, [name, format].compact.join('.')].compact.join('/')
[base_path, [name, locale, format].compact.join('.')].compact.join('/')
end
memoize :path_without_extension

def path_without_format_and_extension
[base_path, name].compact.join('/')
[base_path, [name, locale].compact.join('.')].compact.join('/')
end
memoize :path_without_format_and_extension

Expand Down Expand Up @@ -207,6 +208,10 @@ def valid_extension?(extension)
!Template.registered_template_handler(extension).nil?
end

def valid_locale?(locale)
I18n.available_locales.include?(locale.to_sym)
end

def find_full_path(path, load_paths)
load_paths = Array(load_paths) + [nil]
load_paths.each do |load_path|
Expand All @@ -217,19 +222,42 @@ def find_full_path(path, load_paths)
end

# Returns file split into an array
# [base_path, name, format, extension]
# [base_path, name, locale, format, extension]
def split(file)
if m = file.match(/^(.*\/)?([^\.]+)\.?(\w+)?\.?(\w+)?\.?(\w+)?$/)
if valid_extension?(m[5]) # Multipart formats
[m[1], m[2], "#{m[3]}.#{m[4]}", m[5]]
elsif valid_extension?(m[4]) # Single format
[m[1], m[2], m[3], m[4]]
elsif valid_extension?(m[3]) # No format
[m[1], m[2], nil, m[3]]
if m = file.match(/^(.*\/)?([^\.]+)\.(.*)$/)
base_path = m[1]
name = m[2]
extensions = m[3]
else
return
end

locale = nil
format = nil
extension = nil

if m = extensions.match(/^(\w+)?\.?(\w+)?\.?(\w+)?\.?/)
if valid_locale?(m[1]) && m[2] && valid_extension?(m[3]) # All three
locale = m[1]
format = m[2]
extension = m[3]
elsif m[1] && m[2] && valid_extension?(m[3]) # Multipart formats
format = "#{m[1]}.#{m[2]}"
extension = m[3]
elsif valid_extension?(m[1]) # Just extension
extension = m[1]
elsif valid_locale?(m[1]) && valid_extension?(m[2]) # locale and extension
locale = m[1]
extension = m[2]
elsif valid_extension?(m[2]) # format and extension
format = m[1]
extension = m[2]
else # No extension
[m[1], m[2], m[3], nil]
format = m[1]
end
end

[base_path, name, locale, format, extension]
end
end
end
4 changes: 4 additions & 0 deletions actionpack/test/abstract_unit.rb
Expand Up @@ -32,6 +32,10 @@

ActionController::Base.session_store = nil

# Register danish language for testing
I18n.backend.store_translations 'da', {}
ORIGINAL_LOCALES = I18n.available_locales

FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
ActionController::Base.view_paths = FIXTURE_LOAD_PATH

Expand Down
1 change: 1 addition & 0 deletions actionpack/test/fixtures/test/hello_world.da.html.erb
@@ -0,0 +1 @@
Hey verden
15 changes: 15 additions & 0 deletions actionpack/test/template/render_test.rb
Expand Up @@ -5,6 +5,13 @@ module RenderTestCases
def setup_view(paths)
@assigns = { :secret => 'in the sauce' }
@view = ActionView::Base.new(paths, @assigns)

# Reload and register danish language for testing
I18n.reload!
I18n.backend.store_translations 'da', {}

# Ensure original are still the same since we are reindexing view paths
assert_equal ORIGINAL_LOCALES, I18n.available_locales
end

def test_render_file
Expand All @@ -19,6 +26,14 @@ def test_render_file_without_specific_extension
assert_equal "Hello world!", @view.render(:file => "test/hello_world")
end

def test_render_file_with_localization
old_locale = I18n.locale
I18n.locale = :da
assert_equal "Hey verden", @view.render(:file => "test/hello_world")
ensure
I18n.locale = old_locale
end

def test_render_file_at_top_level
assert_equal 'Elastica', @view.render(:file => '/shared')
end
Expand Down

4 comments on commit a98cd7c

@nicolasblanco
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

when I use localized template like : index.fr.html.erb, the Content-Type header sent by the server becomes “fr.html; charset=utf-8” instead of the standard “text/html; charset=utf-8”.

Because of this problem, my browser (Firefox 3) sets a bad character decoder (ISO instead of UTF-8) and my views are broken.

@josevalim
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@slainer68, I think you should warn that in the mailing list. This seems like high priority!

@boof
Copy link

@boof boof commented on a98cd7c Feb 3, 2009

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a Lighthouse ticket would be good.

@nicolasblanco
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK.

More information : the bad Content-Type is only sent when the locale is not properly loaded/valid (for example in a new Rails application, you set the locale to :fr in the environment.rb file but you don’t put a fr.yml file).

But IMHO, the Content-Type sent by Rails should be valid even if the locale is not valid/loaded.

Please sign in to comment.