fdl_translator 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/CHANGELOG +0 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +149 -0
- data/Rakefile +76 -0
- data/VERSION.yml +5 -0
- data/init.rb +1 -0
- data/install.rb +3 -0
- data/lib/translator.rb +360 -0
- data/tasks/translator.rake +23 -0
- data/test/fixtures/app/controllers/blog_posts_controller.rb +89 -0
- data/test/fixtures/app/helpers/blog_posts_helper.rb +10 -0
- data/test/fixtures/app/models/blog_comment_mailer.rb +10 -0
- data/test/fixtures/app/models/blog_post.rb +14 -0
- data/test/fixtures/app/views/blog_comment_mailer/comment_notification.rhtml +5 -0
- data/test/fixtures/app/views/blog_posts/_footer.erb +3 -0
- data/test/fixtures/app/views/blog_posts/about.erb +6 -0
- data/test/fixtures/app/views/blog_posts/archives.erb +2 -0
- data/test/fixtures/app/views/blog_posts/missing_translation.erb +2 -0
- data/test/fixtures/app/views/blog_posts/show.erb +4 -0
- data/test/fixtures/app/views/layouts/blog_layout.erb +9 -0
- data/test/fixtures/app/views/shared/_header.erb +2 -0
- data/test/fixtures/schema.rb +11 -0
- data/test/locales/en.yml +56 -0
- data/test/locales/es.yml +16 -0
- data/test/test_helper.rb +90 -0
- data/test/translator_test.rb +353 -0
- data/translator.gemspec +63 -0
- data/uninstall.rb +1 -0
- metadata +90 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
# Internationalization tasks
|
4
|
+
namespace :i18n do
|
5
|
+
|
6
|
+
desc "Validates YAML locale bundles"
|
7
|
+
task :validate_yml => [:environment] do |t, args|
|
8
|
+
|
9
|
+
# Grab all the yaml bundles in config/locales
|
10
|
+
bundles = Dir.glob(File.join(RAILS_ROOT, 'config', 'locales', '**', '*.yml'))
|
11
|
+
|
12
|
+
# Attempt to load each bundle
|
13
|
+
bundles.each do |bundle|
|
14
|
+
|
15
|
+
begin
|
16
|
+
YAML.load_file( bundle )
|
17
|
+
rescue Exception => exc
|
18
|
+
puts "Error loading: #{bundle}"
|
19
|
+
puts exc.to_s
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# Stub a Blog Posts controller
|
2
|
+
class BlogPostsController < ActionController::Base
|
3
|
+
|
4
|
+
# Sets up view paths so tests will work
|
5
|
+
before_filter :fix_view_paths
|
6
|
+
|
7
|
+
# Simulate auth filter
|
8
|
+
before_filter :authorize, :only => [:admin]
|
9
|
+
|
10
|
+
layout "blog_layout", :only => :show_with_layout
|
11
|
+
|
12
|
+
def index
|
13
|
+
# Pull out sample strings for index to the fake blog
|
14
|
+
@page_title = t('title')
|
15
|
+
@intro = translate(:intro, :owner => "Ricky Rails")
|
16
|
+
render :nothing => true, :layout => false
|
17
|
+
end
|
18
|
+
|
19
|
+
def show
|
20
|
+
# Sample blog post
|
21
|
+
render :template => "blog_posts/show"
|
22
|
+
end
|
23
|
+
|
24
|
+
def about
|
25
|
+
# About page
|
26
|
+
render :template => "blog_posts/about"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Render the show action with a layout
|
30
|
+
def show_with_layout
|
31
|
+
render :template => "blog_posts/show"
|
32
|
+
end
|
33
|
+
|
34
|
+
# The archives action references a view helper
|
35
|
+
def archives
|
36
|
+
render :template => "blog_posts/archives"
|
37
|
+
end
|
38
|
+
|
39
|
+
# View that has a key that doesn't reference a valid string
|
40
|
+
def missing_translation
|
41
|
+
render :template => "blog_posts/missing_translation"
|
42
|
+
end
|
43
|
+
|
44
|
+
def different_formats
|
45
|
+
# Get the same tagline using the different formats
|
46
|
+
@taglines = []
|
47
|
+
@taglines << t('global.sub.key') # dot-sep keys
|
48
|
+
@taglines << t('sub.key', :scope => :global) # dot-sep keys with scope
|
49
|
+
@taglines << t('key', :scope => 'global.sub') # string key with dot-sep scope
|
50
|
+
@taglines << t(:key, :scope => 'global.sub') # symbol key with dot-sep score
|
51
|
+
@taglines << t(:key, :scope => %w(global sub))
|
52
|
+
render :nothing => true
|
53
|
+
end
|
54
|
+
|
55
|
+
# Partial template, but stored within this controller
|
56
|
+
def footer_partial
|
57
|
+
render :partial => "footer"
|
58
|
+
end
|
59
|
+
|
60
|
+
# Partial that is shared across controllers
|
61
|
+
def header_partial
|
62
|
+
render :partial => "shared/header"
|
63
|
+
end
|
64
|
+
|
65
|
+
def admin
|
66
|
+
# Simulate an admin page that has a protection scheme
|
67
|
+
end
|
68
|
+
|
69
|
+
def default_value
|
70
|
+
# Get a default value if the string isn't there
|
71
|
+
@title = t('not_there', :default => 'the default')
|
72
|
+
render :nothing => true
|
73
|
+
end
|
74
|
+
|
75
|
+
protected
|
76
|
+
|
77
|
+
# Simulate an auth system that prevents login
|
78
|
+
def authorize
|
79
|
+
# set a flash with a common message
|
80
|
+
flash[:error] = t('flash.invalid_login')
|
81
|
+
redirect_to :action => :index
|
82
|
+
end
|
83
|
+
|
84
|
+
def fix_view_paths
|
85
|
+
# Append the view path to get the correct views/partials
|
86
|
+
self.append_view_path("#{File.dirname(__FILE__)}/../views")
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# A mailer for new comments on the fake blog
|
2
|
+
class BlogCommentMailer < ActionMailer::Base
|
3
|
+
# Send email about new comments
|
4
|
+
def comment_notification
|
5
|
+
@subject = t('subject')
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
# Set the path to where the mail template will be found
|
10
|
+
BlogCommentMailer.template_root = "#{File.dirname(__FILE__)}/../views"
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Model of a blog post, defined in schema.rb
|
2
|
+
class BlogPost < ActiveRecord::Base
|
3
|
+
|
4
|
+
# text for a permalink
|
5
|
+
def self.permalink(url)
|
6
|
+
t('permalink', :url => url)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Has a title, author and body
|
10
|
+
def written_by
|
11
|
+
# Get sting like "Written by Ricky"
|
12
|
+
t('byline', :author => self.author)
|
13
|
+
end
|
14
|
+
end
|
data/test/locales/en.yml
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
en:
|
2
|
+
# Global strings
|
3
|
+
global:
|
4
|
+
sub:
|
5
|
+
key: "Hello i18n World"
|
6
|
+
|
7
|
+
# Controller
|
8
|
+
blog_posts:
|
9
|
+
# shared strings
|
10
|
+
bio: "Hello!"
|
11
|
+
subscribe_feed: "Subscribe to my feed!"
|
12
|
+
|
13
|
+
# typical actions
|
14
|
+
index:
|
15
|
+
title: "My Blog Posts"
|
16
|
+
intro: "Welcome to the blog of {{owner}}"
|
17
|
+
# specific post
|
18
|
+
show:
|
19
|
+
title: "Catz Are Cute"
|
20
|
+
body: "My cat {{name}} is the most awesome"
|
21
|
+
category: "catz, lolz"
|
22
|
+
# archives action - key used from a view helper
|
23
|
+
archives:
|
24
|
+
title: "My Blog Archives"
|
25
|
+
# footer partial (non-shared)
|
26
|
+
footer:
|
27
|
+
copyright: "Copyright 2009"
|
28
|
+
|
29
|
+
# Flash messages not specific to one action, but within a single controller
|
30
|
+
flash:
|
31
|
+
invalid_login: "Invalid login"
|
32
|
+
|
33
|
+
# shared partials in the "shared" dir
|
34
|
+
shared:
|
35
|
+
header:
|
36
|
+
blog_name: "Ricky Rocks Rails"
|
37
|
+
|
38
|
+
# Layouts
|
39
|
+
layouts:
|
40
|
+
blog_layout:
|
41
|
+
blog_title: "The Blog of Ricky"
|
42
|
+
|
43
|
+
#
|
44
|
+
# ActiveRecord models (note singular)
|
45
|
+
#
|
46
|
+
blog_post:
|
47
|
+
byline: "Written by {{author}}"
|
48
|
+
permalink: "Permalink to {{url}}"
|
49
|
+
|
50
|
+
#
|
51
|
+
# ActionMailers
|
52
|
+
#
|
53
|
+
blog_comment_mailer:
|
54
|
+
comment_notification:
|
55
|
+
subject: "New Comment Notification"
|
56
|
+
signoff: "Your Faithful Emailing Bot"
|
data/test/locales/es.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Spanish version (pardon the bad translations)
|
2
|
+
es:
|
3
|
+
# Global strings
|
4
|
+
global:
|
5
|
+
sub:
|
6
|
+
key: "Hola i18n Mundo"
|
7
|
+
|
8
|
+
# Controller
|
9
|
+
blog_posts:
|
10
|
+
# shared strings
|
11
|
+
bio: "Hola!"
|
12
|
+
|
13
|
+
# typical actions
|
14
|
+
index:
|
15
|
+
# Purposely has the intro but *not* "title" key
|
16
|
+
intro: "Bienvenidos a el blog de {{owner}}"
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# Load Rails from the app, which allows picking up a frozen rails install
|
2
|
+
# instead of from the gems
|
3
|
+
#
|
4
|
+
# Borrowed from setup in classic_pagination plugin
|
5
|
+
plugin_root = File.join(File.dirname(__FILE__), '..')
|
6
|
+
# is the plugin installed in an application?
|
7
|
+
app_root = plugin_root + '/../../..'
|
8
|
+
|
9
|
+
if File.directory? app_root + '/config'
|
10
|
+
Object.const_set(:RAILS_ENV, ENV["RAILS_ENV"] ||= "test") unless defined?(RAILS_ENV)
|
11
|
+
Object.const_set(:RAILS_ROOT, app_root) unless defined?(RAILS_ROOT)
|
12
|
+
require "#{RAILS_ROOT}/config/environment"
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'pp'
|
16
|
+
require 'test/unit'
|
17
|
+
require 'rubygems'
|
18
|
+
require 'active_support'
|
19
|
+
require 'active_support/test_case'
|
20
|
+
|
21
|
+
require 'action_controller'
|
22
|
+
require 'action_controller/test_process'
|
23
|
+
require 'action_mailer'
|
24
|
+
require 'active_record'
|
25
|
+
require 'active_record/fixtures'
|
26
|
+
|
27
|
+
require 'action_pack'
|
28
|
+
require 'action_view'
|
29
|
+
require 'action_view/helpers'
|
30
|
+
|
31
|
+
# Load the Translator init after loading Rails
|
32
|
+
require File.dirname(__FILE__) + '/../init'
|
33
|
+
|
34
|
+
# Set up an ActiveRecord connection to sqlite db for testing
|
35
|
+
# Define the connector
|
36
|
+
class ActiveRecordTestConnector
|
37
|
+
cattr_accessor :able_to_connect
|
38
|
+
cattr_accessor :connected
|
39
|
+
|
40
|
+
# Set our defaults
|
41
|
+
self.connected = false
|
42
|
+
self.able_to_connect = true
|
43
|
+
|
44
|
+
class << self
|
45
|
+
def setup
|
46
|
+
unless self.connected || !self.able_to_connect
|
47
|
+
setup_connection
|
48
|
+
load_schema
|
49
|
+
self.connected = true
|
50
|
+
end
|
51
|
+
rescue Exception => e # errors from ActiveRecord setup
|
52
|
+
$stderr.puts "\nSkipping ActiveRecord assertion tests: #{e}"
|
53
|
+
self.able_to_connect = false
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def setup_connection
|
59
|
+
if Object.const_defined?(:ActiveRecord)
|
60
|
+
defaults = { :database => ':memory:' }
|
61
|
+
begin
|
62
|
+
options = defaults.merge :adapter => 'sqlite3', :timeout => 500
|
63
|
+
ActiveRecord::Base.establish_connection(options)
|
64
|
+
ActiveRecord::Base.configurations = { 'sqlite3_ar_integration' => options }
|
65
|
+
ActiveRecord::Base.connection
|
66
|
+
rescue Exception # errors from establishing a connection
|
67
|
+
$stderr.puts 'SQLite 3 unavailable; trying SQLite 2.'
|
68
|
+
options = defaults.merge :adapter => 'sqlite'
|
69
|
+
ActiveRecord::Base.establish_connection(options)
|
70
|
+
ActiveRecord::Base.configurations = { 'sqlite2_ar_integration' => options }
|
71
|
+
ActiveRecord::Base.connection
|
72
|
+
end
|
73
|
+
|
74
|
+
Object.send(:const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')) unless Object.const_defined?(:QUOTED_TYPE)
|
75
|
+
else
|
76
|
+
raise "Can't setup connection since ActiveRecord isn't loaded."
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Loads the schema.rb
|
81
|
+
def load_schema
|
82
|
+
# Silence the output of creating the db
|
83
|
+
silence_stream(STDOUT) do
|
84
|
+
Dir.glob(File.dirname(__FILE__) + "/fixtures/schema.rb").each {|f| require f}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
ActiveRecordTestConnector.setup
|
@@ -0,0 +1,353 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
# Include the models/helpers directories on the load path.
|
4
|
+
[:models, :helpers, :controllers].each do |path|
|
5
|
+
$:.unshift "#{File.dirname(__FILE__)}/fixtures/app/#{path}"
|
6
|
+
end
|
7
|
+
|
8
|
+
# sample AR model
|
9
|
+
require 'blog_post'
|
10
|
+
# sample ActionMailer
|
11
|
+
require 'blog_comment_mailer'
|
12
|
+
# sample controller
|
13
|
+
require 'blog_posts_controller'
|
14
|
+
|
15
|
+
# Set up simple routing for testing
|
16
|
+
ActionController::Routing::Routes.reload rescue nil
|
17
|
+
ActionController::Routing::Routes.draw do |map|
|
18
|
+
map.connect ':controller/:action/:id'
|
19
|
+
end
|
20
|
+
|
21
|
+
# For Rails 2.2 compat
|
22
|
+
parent_module = ActiveSupport::TestCase
|
23
|
+
|
24
|
+
if Rails::VERSION::MAJOR == 2 && Rails::VERSION::MINOR > 2
|
25
|
+
# Rails 2.3 compat
|
26
|
+
parent_module = ActionController::TestCase
|
27
|
+
end
|
28
|
+
|
29
|
+
# Test Translator functionality
|
30
|
+
class TranslatorTest < parent_module
|
31
|
+
|
32
|
+
def setup
|
33
|
+
# Create test locale bundle
|
34
|
+
I18n.backend = I18n::Backend::Simple.new
|
35
|
+
|
36
|
+
# tell the I18n library where to find your translations
|
37
|
+
I18n.load_path += Dir.glob(File.join(File.dirname(__FILE__), 'locales', '*.{yml,rb}'))
|
38
|
+
|
39
|
+
# reset the locale
|
40
|
+
I18n.default_locale = :en
|
41
|
+
I18n.locale = :en
|
42
|
+
|
43
|
+
# Set up test env
|
44
|
+
@controller = BlogPostsController.new
|
45
|
+
@request = ActionController::TestRequest.new
|
46
|
+
@response = ActionController::TestResponse.new
|
47
|
+
super
|
48
|
+
end
|
49
|
+
|
50
|
+
### ActionController Tests
|
51
|
+
|
52
|
+
# Test that translate gets typical controller scoping
|
53
|
+
def test_controller_simple
|
54
|
+
get :index
|
55
|
+
assert_response :success
|
56
|
+
assert_not_nil assigns
|
57
|
+
# Test that controller could translate
|
58
|
+
assert_equal I18n.t('blog_posts.index.title'), assigns(:page_title)
|
59
|
+
assert_equal I18n.translate('blog_posts.index.intro', :owner => "Ricky Rails"), assigns(:intro)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Test that if something that breaks convention is still processed correctly
|
63
|
+
# This case breaks with standard key hierarchy convention
|
64
|
+
def test_controller_different_formats
|
65
|
+
get :different_formats
|
66
|
+
assert_response :success
|
67
|
+
assert_not_nil assigns(:taglines)
|
68
|
+
|
69
|
+
expected = "Hello i18n World" # copied from en.yml
|
70
|
+
|
71
|
+
assigns(:taglines).each do |str|
|
72
|
+
assert_equal expected, str
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Test call to translate with default value
|
77
|
+
def test_controller_with_defaults
|
78
|
+
get :default_value
|
79
|
+
assert_response :success
|
80
|
+
assert_not_nil assigns(:title)
|
81
|
+
|
82
|
+
# TODO: Need better way to check that the default was only returned as last resort.
|
83
|
+
assert_equal 'the default', assigns(:title)
|
84
|
+
end
|
85
|
+
|
86
|
+
# TODO: Test bulk lookup
|
87
|
+
def test_bulk_lookup
|
88
|
+
# flunk
|
89
|
+
end
|
90
|
+
|
91
|
+
# Translator should raise an exception on a leading dot key to
|
92
|
+
# preserve Rails 2.3 behavior. It is caught & handled
|
93
|
+
def test_leading_dot_key
|
94
|
+
assert_raise Translator::TranslatorError do
|
95
|
+
Translator.translate_with_scope(["blog_posts", "show"], ".category")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Test that first the most specific scope will be tried (controller.action) then
|
100
|
+
# back off to just the outer scope (controller)
|
101
|
+
def test_controller_shared_messages
|
102
|
+
get :admin
|
103
|
+
assert_response :redirect
|
104
|
+
|
105
|
+
# Test that t should have tried the outer scope
|
106
|
+
assert_equal I18n.t('blog_posts.flash.invalid_login'), flash[:error]
|
107
|
+
end
|
108
|
+
|
109
|
+
### ActionView Tests
|
110
|
+
|
111
|
+
# Test that translate works in Views.
|
112
|
+
# Also tests that a dotted key (".foo") can be accepted used, since
|
113
|
+
# Rails 2.3 supports it
|
114
|
+
def test_view_show
|
115
|
+
get :show
|
116
|
+
assert_response :success
|
117
|
+
post_title = I18n.translate('blog_posts.show.title')
|
118
|
+
post_body = I18n.t('blog_posts.show.body', :name => 'hobbes') # matches show.erb
|
119
|
+
|
120
|
+
assert_match /#{post_title}/, @response.body
|
121
|
+
assert_match /#{post_body}/, @response.body
|
122
|
+
end
|
123
|
+
|
124
|
+
# Test that layouts can pull strings
|
125
|
+
def test_show_with_layout
|
126
|
+
get :show_with_layout
|
127
|
+
assert_response :success
|
128
|
+
|
129
|
+
blog_title = I18n.t('layouts.blog_layout.blog_title')
|
130
|
+
assert_match /#{blog_title}/, @response.body
|
131
|
+
end
|
132
|
+
|
133
|
+
# Test that partials pull strings from their own key
|
134
|
+
def test_view_partial
|
135
|
+
get :footer_partial
|
136
|
+
assert_response :success
|
137
|
+
|
138
|
+
footer = I18n.t('blog_posts.footer.copyright')
|
139
|
+
assert_match /#{footer}/, @response.body
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_header_partial
|
143
|
+
get :header_partial
|
144
|
+
assert_response :success
|
145
|
+
|
146
|
+
blog_name = I18n.t('shared.header.blog_name')
|
147
|
+
assert_match /#{blog_name}/, @response.body
|
148
|
+
end
|
149
|
+
|
150
|
+
# Test that view helpers inherit correct scoping
|
151
|
+
def test_view_helpers
|
152
|
+
get :archives
|
153
|
+
assert_response :success
|
154
|
+
|
155
|
+
archives_title = I18n.t('blog_posts.archives.title')
|
156
|
+
assert_match /#{archives_title}/, @response.body
|
157
|
+
end
|
158
|
+
|
159
|
+
# Test that original behavior of TranslationHelper is not undone.
|
160
|
+
# It adds a <span class="translation_missing"> that should still be there
|
161
|
+
def test_missing_translation_show_in_span
|
162
|
+
Translator.strict_mode(false)
|
163
|
+
|
164
|
+
get :missing_translation
|
165
|
+
assert_response :success
|
166
|
+
|
167
|
+
# behavior added by TranslationHelper
|
168
|
+
assert_match /span class="translation_missing"/, @response.body, "Should be a span tag translation_missing"
|
169
|
+
end
|
170
|
+
|
171
|
+
# Test that strict mode prevents TranslationHelper from adding span.
|
172
|
+
def test_strict_mode_in_views
|
173
|
+
Translator.strict_mode(true)
|
174
|
+
|
175
|
+
get :missing_translation
|
176
|
+
assert_response :error
|
177
|
+
assert_match /18n::MissingTranslationData/, @response.body, "Exception should be for a missing translation"
|
178
|
+
end
|
179
|
+
|
180
|
+
### ActionMailer Tests
|
181
|
+
|
182
|
+
def test_mailer
|
183
|
+
mail = BlogCommentMailer.create_comment_notification
|
184
|
+
# Subject is fetched from the mailer action
|
185
|
+
subject = I18n.t('blog_comment_mailer.comment_notification.subject')
|
186
|
+
|
187
|
+
# Signoff is fetched in the mail template (via addition to ActionView)
|
188
|
+
signoff = I18n.t('blog_comment_mailer.comment_notification.signoff')
|
189
|
+
|
190
|
+
assert_match /#{subject}/, mail.body
|
191
|
+
assert_match /#{signoff}/, mail.body
|
192
|
+
end
|
193
|
+
|
194
|
+
### ActiveRecord tests
|
195
|
+
|
196
|
+
# Test that a model's method can call translate
|
197
|
+
def test_model_calling_translate
|
198
|
+
post = nil
|
199
|
+
author = "Ricky"
|
200
|
+
assert_nothing_raised do
|
201
|
+
post = BlogPost.create(:title => "First Post!", :body => "Starting my new blog about RoR", :author => author)
|
202
|
+
end
|
203
|
+
assert_not_nil post
|
204
|
+
|
205
|
+
assert_equal I18n.t('blog_post.byline', :author => author), post.written_by
|
206
|
+
end
|
207
|
+
|
208
|
+
# Test that the translate method is added as a class method too so that it can
|
209
|
+
# be used in validate calls, etc.
|
210
|
+
def test_class_method_translate
|
211
|
+
|
212
|
+
url = "http://ricky.blog"
|
213
|
+
# Call a static method
|
214
|
+
assert_equal I18n.t('blog_post.permalink', :url => url), BlogPost.permalink(url)
|
215
|
+
end
|
216
|
+
|
217
|
+
### TestUnit helpers
|
218
|
+
|
219
|
+
def test_strict_mode
|
220
|
+
Translator.strict_mode(true)
|
221
|
+
|
222
|
+
# With strict mode on, exception should be thrown
|
223
|
+
assert_raise I18n::MissingTranslationData do
|
224
|
+
str = "Exception should be raised #{I18n.t('the_missing_key')}"
|
225
|
+
end
|
226
|
+
|
227
|
+
Translator.strict_mode(false)
|
228
|
+
|
229
|
+
assert_nothing_raised do
|
230
|
+
str = "Exception should not be raised #{I18n.t('the_missing_key')}"
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# Fetch a miss
|
235
|
+
def test_assert_translated
|
236
|
+
# Within the assert_translated block, any missing keys fail the test
|
237
|
+
assert_raise Test::Unit::AssertionFailedError do
|
238
|
+
assert_translated do
|
239
|
+
str = "Exception should be raised #{I18n.t('the_missing_key')}"
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
assert_nothing_raised do
|
244
|
+
str = "Exception should not be raised #{I18n.t('the_missing_key')}"
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
# Test that marker text appears in when using pseudo-translation
|
249
|
+
def test_pseudo_translate
|
250
|
+
Translator.pseudo_translate(true)
|
251
|
+
|
252
|
+
# Create a blog post that uses translate to create a byline
|
253
|
+
blog_post = BlogPost.create!(:author => "Ricky")
|
254
|
+
assert_not_nil blog_post
|
255
|
+
|
256
|
+
assert_match Translator.pseudo_prepend, blog_post.written_by, "Should start with prepend text"
|
257
|
+
assert_match Translator.pseudo_append, blog_post.written_by, "Should end with append text"
|
258
|
+
end
|
259
|
+
|
260
|
+
# Test that markers can be changed
|
261
|
+
def test_pseudo_translate_with_diff_markers
|
262
|
+
Translator.pseudo_translate(true)
|
263
|
+
|
264
|
+
start_marker = "!!"
|
265
|
+
end_marker = "%%"
|
266
|
+
|
267
|
+
# Set the new markers
|
268
|
+
Translator.pseudo_prepend = start_marker
|
269
|
+
Translator.pseudo_append = end_marker
|
270
|
+
|
271
|
+
get :footer_partial
|
272
|
+
assert_response :success
|
273
|
+
|
274
|
+
# Test that the view has the pseudo-translated strings
|
275
|
+
copyright = I18n.t('blog_posts.footer.copyright')
|
276
|
+
assert_match /#{start_marker + copyright + end_marker}/, @response.body
|
277
|
+
end
|
278
|
+
|
279
|
+
# Test that if fallback mode is enabled, the default locale is used if
|
280
|
+
# the set locale can't be found
|
281
|
+
def test_fallback
|
282
|
+
# Enable fallback mode
|
283
|
+
Translator.fallback(true)
|
284
|
+
|
285
|
+
# Set the locale to Spanish
|
286
|
+
I18n.locale = :es
|
287
|
+
|
288
|
+
# The index action fetchs 2 keys - 1 has a Spanish translation (intro), 1 does not
|
289
|
+
get :index
|
290
|
+
assert_response :success
|
291
|
+
assert_not_nil assigns
|
292
|
+
|
293
|
+
# Test that controller could translate the intro from spanish
|
294
|
+
assert_equal I18n.t('blog_posts.index.intro', :owner => "Ricky Rails"), assigns(:intro)
|
295
|
+
|
296
|
+
# Test that global strings are found correctly when they have a prefix
|
297
|
+
assert_equal I18n.t('global.sub.key', :locale => :es), @controller.t('global.sub.key')
|
298
|
+
|
299
|
+
# Should find the English version
|
300
|
+
I18n.locale = :en # reset local so call to I18n pulls correct string
|
301
|
+
assert_equal I18n.translate('blog_posts.index.title'), assigns(:page_title)
|
302
|
+
|
303
|
+
# Test that global strings are found correctly when they have a prefix
|
304
|
+
assert_equal I18n.t('global.sub.key', :locale => :en), @controller.t('global.sub.key')
|
305
|
+
end
|
306
|
+
|
307
|
+
# Test that fallback
|
308
|
+
def test_fallback_with_scoping_backoff
|
309
|
+
|
310
|
+
# Enable fallback mode
|
311
|
+
Translator.fallback(true)
|
312
|
+
|
313
|
+
# Set the locale to Spanish
|
314
|
+
I18n.locale = :es
|
315
|
+
|
316
|
+
get :about
|
317
|
+
assert_response :success
|
318
|
+
|
319
|
+
# Test that the Spanish version was found
|
320
|
+
bio = I18n.t('blog_posts.bio', :locale => :es)
|
321
|
+
assert_match /#{bio}/, @response.body
|
322
|
+
|
323
|
+
# Only English version of this string
|
324
|
+
subscribe = I18n.t('blog_posts.subscribe_feed', :locale => :en)
|
325
|
+
assert_match /#{subscribe}/, @response.body
|
326
|
+
end
|
327
|
+
|
328
|
+
# Test that we can set up a callback for missing translations
|
329
|
+
def test_missing_translation_callback
|
330
|
+
test_exception = nil
|
331
|
+
test_key = nil
|
332
|
+
test_options = nil
|
333
|
+
|
334
|
+
Translator.set_missing_translation_callback do |ex, key, options|
|
335
|
+
test_exception = ex
|
336
|
+
test_key = key
|
337
|
+
test_options = options
|
338
|
+
end
|
339
|
+
|
340
|
+
get :missing_translation
|
341
|
+
assert_response :success
|
342
|
+
assert_equal "missing_string", test_key
|
343
|
+
assert_not_nil test_options
|
344
|
+
assert_not_nil test_exception
|
345
|
+
end
|
346
|
+
|
347
|
+
# Test the generic translate method on Translator that does lookup without a scope, but includes fallback behavior.
|
348
|
+
def test_generic_translate_methods
|
349
|
+
assert_equal I18n.t('blog_posts.index.intro', :owner => "Ricky Rails"), Translator.translate('blog_posts.index.intro', :owner => "Ricky Rails")
|
350
|
+
assert_equal I18n.t('blog_posts.footer.copyright'), Translator.t('blog_posts.footer.copyright')
|
351
|
+
end
|
352
|
+
|
353
|
+
end
|