radiant-language_redirect-extension 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile ADDED
@@ -0,0 +1,52 @@
1
+ h1. Language Redirect
2
+
3
+ Redirects to the appropriate language section based on the content encoding preferred by the Web browser.
4
+
5
+ h2. Version History
6
+
7
+ * 2/2013 - Radiant 1.1.x compatible, fix deprecations, gemify
8
+ * 5/2011 - Radiant 1.0 compatible
9
+ * 4/2009 - Radiant 0.8 compatible
10
+ * 2/2009 - Radiant 0.7 compatible
11
+ * 1/2007 - Intital Import
12
+
13
+ h2. Installation
14
+
15
+ * add to your Gemfile: <code>gem "radiant-language_redirect-extension"</code>
16
+ * run bundle
17
+
18
+ h2. Usage
19
+
20
+ You can add a "config" part to the page which maps languages to URLs
21
+ in the following format:
22
+
23
+ <pre>
24
+ lang: url
25
+ lang: url
26
+ ...
27
+ </pre>
28
+
29
+ Where "lang" refers to a language code and "url" refers to the URL
30
+ which should be redirected to based on the preferred content
31
+ encoding of the Web browser.
32
+
33
+ The following listing is a sample "config" page part:
34
+ <pre>
35
+ en: /en/
36
+ ja: /ja/
37
+ *: /en/
38
+ </pre>
39
+ In this example, when the browser prefers English content it will be
40
+ redirected to the "/en/" URL. When it prefers Japanese content it will
41
+ be redirected to the "/ja/" URL. In the event that the browser prefers
42
+ something other than English or Japanese content, they will be
43
+ redirected to the "/en/" URL. This is what the "*" in the last entry
44
+ does. URLs can be either relative (without "http://hostname.tld") or
45
+ absolute (with "http://hostname.tld").
46
+
47
+ If no "config" part is specified the behavior will force the page to
48
+ redirect to the "/en/" folder.
49
+
50
+ h2. Credits
51
+
52
+ Created by "Giovanni Intini":http://tempe.st/about/, maintained by "contributors":https://github.com/intinig/radiant_language_redirect_extension/network
data/Rakefile ADDED
@@ -0,0 +1,137 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gem|
4
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
5
+ gem.name = "radiant-language_redirect-extension"
6
+ gem.homepage = "https://github.com/avonderluft/radiant-language_redirect-extension"
7
+ gem.license = "MIT"
8
+ gem.summary = %Q{Language Redirect Extension for Radiant CMS}
9
+ gem.description = %Q{Redirects to the appropriate language section based on the content encoding preferred by the Web browser.}
10
+ gem.email = "avonderluft@avlux.net"
11
+ gem.authors = ["Giovanni Intini", "Andrew vonderLuft"]
12
+ gem.add_dependency 'radiant', ">=1.1.3"
13
+ end
14
+ rescue LoadError
15
+ puts "Jeweler (or a dependency) not available. This is only required if you plan to package language_redirect as a gem."
16
+ end
17
+
18
+ # I think this is the one that should be moved to the extension Rakefile template
19
+
20
+ # In rails 1.2, plugins aren't available in the path until they're loaded.
21
+ # Check to see if the rspec plugin is installed first and require
22
+ # it if it is. If not, use the gem version.
23
+
24
+ # Determine where the RSpec plugin is by loading the boot
25
+ unless defined? RADIANT_ROOT
26
+ ENV["RAILS_ENV"] = "test"
27
+ case
28
+ when ENV["RADIANT_ENV_FILE"]
29
+ require File.dirname(ENV["RADIANT_ENV_FILE"]) + "/boot"
30
+ when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
31
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../")}/config/boot"
32
+ else
33
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../")}/config/boot"
34
+ end
35
+ end
36
+
37
+ require 'rake'
38
+ require 'rdoc/task'
39
+ require 'rake/testtask'
40
+
41
+ rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
42
+ $LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
43
+ require 'spec/rake/spectask'
44
+ # require 'spec/translator'
45
+
46
+ # Cleanup the RADIANT_ROOT constant so specs will load the environment
47
+ Object.send(:remove_const, :RADIANT_ROOT)
48
+
49
+ extension_root = File.expand_path(File.dirname(__FILE__))
50
+
51
+ task :default => :spec
52
+ task :stats => "spec:statsetup"
53
+
54
+ desc "Run all specs in spec directory"
55
+ Spec::Rake::SpecTask.new(:spec) do |t|
56
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
57
+ t.spec_files = FileList['spec/**/*_spec.rb']
58
+ end
59
+
60
+ namespace :spec do
61
+ desc "Run all specs in spec directory with RCov"
62
+ Spec::Rake::SpecTask.new(:rcov) do |t|
63
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
64
+ t.spec_files = FileList['spec/**/*_spec.rb']
65
+ t.rcov = true
66
+ t.rcov_opts = ['--exclude', 'spec', '--rails']
67
+ end
68
+
69
+ desc "Print Specdoc for all specs"
70
+ Spec::Rake::SpecTask.new(:doc) do |t|
71
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
72
+ t.spec_files = FileList['spec/**/*_spec.rb']
73
+ end
74
+
75
+ [:models, :controllers, :views, :helpers].each do |sub|
76
+ desc "Run the specs under spec/#{sub}"
77
+ Spec::Rake::SpecTask.new(sub) do |t|
78
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
79
+ t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
80
+ end
81
+ end
82
+
83
+ # Hopefully no one has written their extensions in pre-0.9 style
84
+ # desc "Translate specs from pre-0.9 to 0.9 style"
85
+ # task :translate do
86
+ # translator = ::Spec::Translator.new
87
+ # dir = RAILS_ROOT + '/spec'
88
+ # translator.translate(dir, dir)
89
+ # end
90
+
91
+ # Setup specs for stats
92
+ task :statsetup do
93
+ require 'code_statistics'
94
+ ::STATS_DIRECTORIES << %w(Model\ specs spec/models)
95
+ ::STATS_DIRECTORIES << %w(View\ specs spec/views)
96
+ ::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers)
97
+ ::STATS_DIRECTORIES << %w(Helper\ specs spec/views)
98
+ ::CodeStatistics::TEST_TYPES << "Model specs"
99
+ ::CodeStatistics::TEST_TYPES << "View specs"
100
+ ::CodeStatistics::TEST_TYPES << "Controller specs"
101
+ ::CodeStatistics::TEST_TYPES << "Helper specs"
102
+ ::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
103
+ end
104
+
105
+ namespace :db do
106
+ namespace :fixtures do
107
+ desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
108
+ task :load => :environment do
109
+ require 'active_record/fixtures'
110
+ ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
111
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'spec', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
112
+ Fixtures.create_fixtures('spec/fixtures', File.basename(fixture_file, '.*'))
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ desc 'Generate documentation for the language_redirect extension.'
120
+ Rake::RDocTask.new(:rdoc) do |rdoc|
121
+ rdoc.rdoc_dir = 'rdoc'
122
+ rdoc.title = 'LanguageRedirectExtension'
123
+ rdoc.options << '--line-numbers' << '--inline-source'
124
+ rdoc.rdoc_files.include('README')
125
+ rdoc.rdoc_files.include('lib/**/*.rb')
126
+ end
127
+
128
+ # For extensions that are in transition
129
+ desc 'Test the language_redirect extension.'
130
+ Rake::TestTask.new(:test) do |t|
131
+ t.libs << 'lib'
132
+ t.pattern = 'test/**/*_test.rb'
133
+ t.verbose = true
134
+ end
135
+
136
+ # Load any custom rakefiles for extension
137
+ Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,66 @@
1
+ class LanguageRedirectPage < Page
2
+
3
+ def headers
4
+ {
5
+ 'Status' => "301 Redirect",
6
+ 'Location' => location,
7
+ 'Vary' => "Accept-Language"
8
+ }
9
+ end
10
+
11
+ def render
12
+ "<html><body>301 Redirect</body></html>"
13
+ end
14
+
15
+ def cache?
16
+ false
17
+ end
18
+
19
+ def response_code
20
+ 301
21
+ end
22
+
23
+ def find_by_url(url, live=true, clean=true)
24
+ found = super
25
+ if (found.nil? || found.is_a?(FileNotFoundPage)) &&
26
+ location_map.values.all? {|target| clean_url(url) !~ Regexp.new(target) }
27
+ self
28
+ else
29
+ found
30
+ end
31
+ end
32
+ alias find_by_path find_by_url
33
+
34
+ protected
35
+ def config
36
+ YAML.load(render_part('config'))
37
+ end
38
+
39
+ def languages
40
+ langs = (@request.env["HTTP_ACCEPT_LANGUAGE"] || "").split(/[,\s]+/)
41
+ langs_with_weights = langs.map do |ele|
42
+ both = ele.split(/;q=/)
43
+ lang = both[0].split('-').first
44
+ weight = both[1] ? Float(both[1]) : 1
45
+ [-weight, lang]
46
+ end.sort_by(&:first).map(&:last)
47
+ end
48
+
49
+ def location
50
+ path = location_map[languages.find { |lang| location_map[lang] }]
51
+ path ||= location_map["*"] || '/en/'
52
+ path += request.request_uri
53
+ path.gsub!(%r{([^:])//}, '\1/')
54
+ if path =~ %r{[:][/][/]}
55
+ path
56
+ else
57
+ path.sub!(%r{^([^/])}, '/\1')
58
+ @request.protocol + @request.host_with_port + path
59
+ end
60
+ end
61
+
62
+ def location_map
63
+ @location_map ||= config
64
+ end
65
+
66
+ end
@@ -0,0 +1,11 @@
1
+ class LanguageRedirectExtension < Radiant::Extension
2
+ version "#{File.read(File.expand_path(File.dirname(__FILE__)) + '/VERSION')}"
3
+ description "Enables redirects to the appropriate language section based on the content encoding preferred by the Web browser."
4
+ url "https://github.com/avonderluft/radiant_language_redirect_extension"
5
+
6
+ def activate
7
+ Page.send :include, LanguageRedirectTags
8
+ LanguageRedirectPage
9
+ end
10
+
11
+ end
@@ -0,0 +1,90 @@
1
+ module LanguageRedirectTags
2
+ include Radiant::Taggable
3
+
4
+ class TagError < StandardError; end
5
+
6
+ desc %{
7
+ Shows the content if the code matches the actual language
8
+
9
+ *Usage:*
10
+ <pre><code><r:if_language code="language" >...</r:if_language></code></pre>
11
+ }
12
+ tag 'if_language' do |tag|
13
+ tag.expand if tag.attr['code'] == current_language
14
+ end
15
+
16
+ desc %{
17
+ Shows the content unless the code matches the actual language
18
+
19
+ *Usage:*
20
+ <pre><code><r:unless_language code="language" >...</r:unless_language></code></pre>
21
+ }
22
+ tag 'unless_language' do |tag|
23
+ tag.expand unless tag.attr['code'] == current_language
24
+ end
25
+
26
+ desc %{
27
+ Shows a language chooser list separated by the characters supplied with the 'separator' attribute. By default, 'separator' is set to |.
28
+ If the 'upcase' attribute is set to false, the language description will be uppercase. By default, 'upcase' is set to true.
29
+ If the 'singleletter' attribute is set to false, the language description will show only the first letter. By default, 'singleletter' is set to true.
30
+
31
+ *Usage:*
32
+ <pre><code><r:choose_language [separator="|"] [upcase="true|false] [singleletter="true|false"] /></code></pre>
33
+ }
34
+ tag 'languageswitch' do |tag|
35
+ upcase = tag.attr.has_key?('upcase') && tag.attr['upcase']=='false' ? nil : true
36
+ singleletter = tag.attr.has_key?('singleletter') && tag.attr['singleletter']=='false' ? nil : true
37
+ separator = tag.attr['separator'] || "|"
38
+
39
+ html = '<ul>'
40
+ config = language_config(self)
41
+ config.delete('*')
42
+ position = 1
43
+ config.each do |key, value|
44
+ key = key.upcase if upcase
45
+ key = key.split(//)[0] if singleletter
46
+ if request.request_uri.starts_with? value
47
+ html += "<li class='active_language'>#{key}</li>"
48
+ else
49
+ html += "<li><a href='#{value}'>#{key}</a></li>"
50
+ end
51
+ html += "<li>#{separator}</li>" if position != config.length
52
+ position = position + 1
53
+ end
54
+ html += '</ul>'
55
+ end
56
+
57
+ tag 'breadcrumbs' do |tag|
58
+ page = tag.locals.page
59
+ breadcrumbs = [tag.render('breadcrumb')]
60
+ nolinks = (tag.attr['nolinks'] == 'true')
61
+ # Remove LanguageRedirect pages from the hierarchy (preferably the root)
62
+ page.ancestors.reject {|p| p.is_a?(LanguageRedirectPage) }.each do |ancestor|
63
+ tag.locals.page = ancestor
64
+ if nolinks
65
+ breadcrumbs.unshift tag.render('breadcrumb')
66
+ else
67
+ breadcrumbs.unshift %{<a href="#{tag.render('url')}">#{tag.render('breadcrumb')}</a>}
68
+ end
69
+ end
70
+ separator = tag.attr['separator'] || ' &gt; '
71
+ breadcrumbs.join(separator)
72
+ end
73
+
74
+ protected
75
+
76
+ def current_language
77
+ config = language_config(self)
78
+ config.each do |key, value|
79
+ return key if request.request_uri.starts_with? value
80
+ end
81
+ end
82
+
83
+ def language_config(page)
84
+ if page.class == LanguageRedirectPage
85
+ YAML.load(page.render_part(:config))
86
+ elsif page.parent
87
+ language_config(page.parent)
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,17 @@
1
+ namespace :radiant do
2
+ namespace :extensions do
3
+ namespace :language_redirect do
4
+
5
+ desc "Runs the migration of the Language Redirect extension"
6
+ task :migrate do
7
+ require 'extension_migrator'
8
+ if ENV["VERSION"]
9
+ LanguageRedirectExtension.migrator.migrate(ENV["VERSION"].to_i)
10
+ else
11
+ LanguageRedirectExtension.migrator.migrate
12
+ end
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ class LanguageRedirectDataset < Dataset::Base
2
+ uses :pages
3
+
4
+ def load
5
+ Page.update_all({:class_name => "LanguageRedirectPage"}, "id = #{page_id(:home)}")
6
+ end
7
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe "LanguageRedirectPage" do
4
+
5
+ before :each do
6
+ @request = ActionController::TestRequest.new
7
+ @response = ActionController::TestResponse.new
8
+ @page = LanguageRedirectPage.new
9
+ @page.stub!(:url).and_return('/')
10
+ @page.parts.build(:name => 'config', :content => {'de' => '/de/', 'es' => '/es/', '*' => '/en/'}.to_yaml)
11
+ @page.parts[0].draft_content = @page.parts[0].content if defined? ConcurrentDraft
12
+ @request.request_uri = '/'
13
+ end
14
+
15
+ it "should select the * entry when no language is given" do
16
+ @page.process(@request, @response)
17
+ @response.should be_redirect
18
+ @response.redirect_url.should == "http://test.host/en/"
19
+ end
20
+
21
+ it "should select the * entry when no language matches" do
22
+ @request.env['HTTP_ACCEPT_LANGUAGE'] = "jp, fr"
23
+ @page.process(@request, @response)
24
+ @response.should be_redirect
25
+ @response.redirect_url.should == "http://test.host/en/"
26
+ end
27
+
28
+ it "should select the first matching language in order given (when all weights are same)" do
29
+ @request.env['HTTP_ACCEPT_LANGUAGE'] = "es, de, en"
30
+ @page.process(@request, @response)
31
+ @response.should be_redirect
32
+ @response.redirect_url.should == "http://test.host/es/"
33
+ end
34
+
35
+ it "should select the first matching language with the highest weight" do
36
+ @request.env['HTTP_ACCEPT_LANGUAGE'] = "de;q=0.7, es;q=0.9, en;q=0.2"
37
+ @page.process(@request, @response)
38
+ @response.should be_redirect
39
+ @response.redirect_url.should == "http://test.host/es/"
40
+ end
41
+
42
+ it "should append the request URI to the redirect location, cleaning up extra slashes" do
43
+ @request.request_uri = '/freight/'
44
+ @page.process(@request, @response)
45
+ @response.redirect_url.should == "http://test.host/en/freight/"
46
+ end
47
+
48
+ describe "when a child page is not found" do
49
+ dataset :language_redirect
50
+
51
+ before :each do
52
+ @page = pages(:home)
53
+ @page.slug = "freight"
54
+ @page.save!
55
+ @page.parts.create!(:name => 'config', :content => {'de' => '/parent/', 'es' => '/es/', '*' => '/en/'}.to_yaml)
56
+ end
57
+
58
+ it "should return self if the URL doesn't match any of the redirect locations" do
59
+ Page.find_by_path('/freight/').should == @page
60
+ end
61
+
62
+ it "should return the found page or nil if the URL matches a redirect location" do
63
+ Page.find_by_path('/en/freight/').should_not == @page
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Adjusted breadcrumbs tag" do
4
+ dataset :pages
5
+
6
+ before :each do
7
+ pages(:home).update_attributes(:class_name => "LanguageRedirectPage")
8
+ end
9
+
10
+ it "should not render the language-redirect page (homepage) in the breadcrumbs" do
11
+ pages(:child_2).should render('<r:breadcrumbs nolinks="true" />').as('Parent &gt; Child 2')
12
+ end
13
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,6 @@
1
+ --colour
2
+ --format
3
+ progress
4
+ --loadby
5
+ mtime
6
+ --reverse
@@ -0,0 +1,39 @@
1
+ unless defined? RADIANT_ROOT
2
+ ENV["RAILS_ENV"] = "test"
3
+ case
4
+ when ENV["RADIANT_ENV_FILE"]
5
+ require ENV["RADIANT_ENV_FILE"]
6
+ when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
7
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../../")}/config/environment"
8
+ else
9
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../")}/config/environment"
10
+ end
11
+ end
12
+ require "#{RADIANT_ROOT}/spec/spec_helper"
13
+
14
+ Dataset::Resolver.default << (File.dirname(__FILE__) + "/datasets")
15
+ Dataset::Resolver.default << (SnippetsExtension.root + "/spec/datasets") if defined?(SnippetsExtension)
16
+ if File.directory?(File.dirname(__FILE__) + "/matchers")
17
+ Dir[File.dirname(__FILE__) + "/matchers/*.rb"].each {|file| require file }
18
+ end
19
+ if File.directory?(File.dirname(__FILE__) + "/matchers")
20
+ Dir[File.dirname(__FILE__) + "/matchers/*.rb"].each {|file| require file }
21
+ end
22
+
23
+ Spec::Runner.configure do |config|
24
+ # config.use_transactional_fixtures = true
25
+ # config.use_instantiated_fixtures = false
26
+ # config.fixture_path = RAILS_ROOT + '/spec/fixtures'
27
+
28
+ # You can declare fixtures for each behaviour like this:
29
+ # describe "...." do
30
+ # fixtures :table_a, :table_b
31
+ #
32
+ # Alternatively, if you prefer to declare them only once, you can
33
+ # do so here, like so ...
34
+ #
35
+ # config.global_fixtures = :table_a, :table_b
36
+ #
37
+ # If you declare global fixtures, be aware that they will be declared
38
+ # for all of your examples, even those that don't use them.
39
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: radiant-language_redirect-extension
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Giovanni Intini
14
+ - Andrew vonderLuft
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2013-02-14 00:00:00 Z
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ hash: 21
28
+ segments:
29
+ - 1
30
+ - 1
31
+ - 3
32
+ version: 1.1.3
33
+ version_requirements: *id001
34
+ name: radiant
35
+ prerelease: false
36
+ type: :runtime
37
+ description: Redirects to the appropriate language section based on the content encoding preferred by the Web browser.
38
+ email: avonderluft@avlux.net
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files:
44
+ - README.textile
45
+ files:
46
+ - README.textile
47
+ - Rakefile
48
+ - VERSION
49
+ - app/models/language_redirect_page.rb
50
+ - language_redirect_extension.rb
51
+ - lib/language_redirect_tags.rb
52
+ - lib/tasks/language_redirect_extension_tasks.rake
53
+ - spec/datasets/language_redirect_dataset.rb
54
+ - spec/models/language_redirect_page_spec.rb
55
+ - spec/models/tags_spec.rb
56
+ - spec/spec.opts
57
+ - spec/spec_helper.rb
58
+ homepage: https://github.com/avonderluft/radiant-language_redirect-extension
59
+ licenses:
60
+ - MIT
61
+ post_install_message:
62
+ rdoc_options: []
63
+
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ hash: 3
81
+ segments:
82
+ - 0
83
+ version: "0"
84
+ requirements: []
85
+
86
+ rubyforge_project:
87
+ rubygems_version: 1.8.25
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: Language Redirect Extension for Radiant CMS
91
+ test_files: []
92
+