aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.gitmodules6
-rw-r--r--INSTALL.txt2
-rw-r--r--app/controllers/application_controller.rb29
-rw-r--r--app/controllers/general_controller.rb23
-rw-r--r--app/controllers/public_body_controller.rb103
-rw-r--r--app/helpers/link_to_helper.rb6
-rw-r--r--app/models/public_body.rb17
-rw-r--r--app/views/admin_public_body/_locale_selector.rhtml10
-rw-r--r--app/views/comment/_comment_form.rhtml2
-rw-r--r--app/views/general/_before_body_end.rhtml16
-rw-r--r--app/views/general/_credits.rhtml5
-rw-r--r--app/views/general/_locale_switcher.rhtml12
-rw-r--r--app/views/general/_orglink.rhtml2
-rw-r--r--app/views/general/custom_css.rhtml1
-rw-r--r--app/views/general/frontpage.rhtml25
-rw-r--r--app/views/general/search.rhtml72
-rw-r--r--app/views/help/about.es.rhtml10
-rw-r--r--app/views/layouts/admin.rhtml17
-rw-r--r--app/views/layouts/default.rhtml96
-rw-r--r--app/views/public_body/show.rhtml56
-rw-r--r--app/views/request/list.rhtml10
-rw-r--r--config/environment.rb19
-rw-r--r--config/environments/development.rb2
-rw-r--r--config/i18n-routes.yml6
-rw-r--r--config/initializers/fast_gettext.rb6
l---------config/locales1
-rw-r--r--config/routes.rb93
-rw-r--r--db/migrate/096_create_translation_tables.rb27
-rw-r--r--db/migrate/097_add_comment_locale.rb10
-rw-r--r--lib/google_translate.rb18
-rw-r--r--lib/i18n_fixes.rb159
-rw-r--r--lib/tasks/gettext.rake5
-rw-r--r--locale/app.pot382
-rw-r--r--locale/en/app.po382
-rw-r--r--locale/es/app.po643
-rw-r--r--public/images/navimg/alaveteli-logo-header.pngbin0 -> 1639 bytes
-rw-r--r--public/images/navimg/alaveteli-logo.pngbin0 -> 2278 bytes
-rw-r--r--public/stylesheets/ie6-custom.css6
-rw-r--r--public/stylesheets/main-custom.css18
-rw-r--r--public/stylesheets/main.css19
-rw-r--r--script/generate_pot.sh9
-rw-r--r--spec/controllers/admin_public_body_controller_spec.rb54
-rw-r--r--spec/controllers/public_body_controller_spec.rb22
-rw-r--r--spec/controllers/track_controller_spec.rb4
-rw-r--r--spec/controllers/user_controller_spec.rb5
-rw-r--r--spec/fixtures/public_body_translations.yml43
-rw-r--r--spec/models/outgoing_mailer_spec.rb2
-rw-r--r--spec/models/xapian_spec.rb1
-rw-r--r--spec/spec_helper.rb10
-rw-r--r--todo.txt8
-rw-r--r--vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb29
m---------vendor/plugins/alavetelitheme0
-rw-r--r--vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/i18n_hacks.rb4
-rw-r--r--vendor/plugins/globalize2/LICENSE21
-rw-r--r--vendor/plugins/globalize2/README.textile86
-rw-r--r--vendor/plugins/globalize2/Rakefile39
-rw-r--r--vendor/plugins/globalize2/VERSION1
-rw-r--r--vendor/plugins/globalize2/generators/db_backend.rb0
-rw-r--r--vendor/plugins/globalize2/generators/templates/db_backend_migration.rb25
-rw-r--r--vendor/plugins/globalize2/globalize2.gemspec81
-rw-r--r--vendor/plugins/globalize2/init.rb1
-rw-r--r--vendor/plugins/globalize2/lib/globalize.rb15
-rw-r--r--vendor/plugins/globalize2/lib/globalize/active_record.rb229
-rw-r--r--vendor/plugins/globalize2/lib/globalize/active_record/adapter.rb80
-rw-r--r--vendor/plugins/globalize2/lib/globalize/active_record/attributes.rb25
-rw-r--r--vendor/plugins/globalize2/lib/globalize/active_record/migration.rb44
-rw-r--r--vendor/plugins/globalize2/lib/i18n/missing_translations_log_handler.rb41
-rw-r--r--vendor/plugins/globalize2/lib/i18n/missing_translations_raise_handler.rb25
-rw-r--r--vendor/plugins/globalize2/test/active_record/fallbacks_test.rb102
-rw-r--r--vendor/plugins/globalize2/test/active_record/migration_test.rb118
-rw-r--r--vendor/plugins/globalize2/test/active_record/sti_translated_test.rb49
-rw-r--r--vendor/plugins/globalize2/test/active_record/translates_test.rb96
-rw-r--r--vendor/plugins/globalize2/test/active_record/translation_class_test.rb30
-rw-r--r--vendor/plugins/globalize2/test/active_record/validation_tests.rb75
-rw-r--r--vendor/plugins/globalize2/test/active_record_test.rb467
-rw-r--r--vendor/plugins/globalize2/test/all.rb2
-rw-r--r--vendor/plugins/globalize2/test/data/models.rb56
-rw-r--r--vendor/plugins/globalize2/test/data/no_globalize_schema.rb11
-rw-r--r--vendor/plugins/globalize2/test/data/schema.rb55
-rw-r--r--vendor/plugins/globalize2/test/i18n/missing_translations_test.rb36
-rw-r--r--vendor/plugins/globalize2/test/test_helper.rb76
-rw-r--r--vendor/plugins/translate_routes/.gitignore4
-rwxr-xr-xvendor/plugins/translate_routes/ChangeLog22
-rwxr-xr-xvendor/plugins/translate_routes/MIT-LICENSE20
-rwxr-xr-xvendor/plugins/translate_routes/README.markdown99
-rwxr-xr-xvendor/plugins/translate_routes/Rakefile22
-rwxr-xr-xvendor/plugins/translate_routes/config/routes_en-US.yml0
-rwxr-xr-xvendor/plugins/translate_routes/config/routes_es-ES.yml1
-rwxr-xr-xvendor/plugins/translate_routes/init.rb1
-rwxr-xr-xvendor/plugins/translate_routes/install.rb1
-rwxr-xr-xvendor/plugins/translate_routes/lib/translate_routes.rb219
-rw-r--r--vendor/plugins/translate_routes/lib/translate_routes_i18n_available_locales.rb23
-rw-r--r--vendor/plugins/translate_routes/lib/translate_routes_test_helper.rb33
-rwxr-xr-xvendor/plugins/translate_routes/tasks/translate_routes_tasks.rake38
-rw-r--r--vendor/plugins/translate_routes/test/locales/routes.yml5
-rwxr-xr-xvendor/plugins/translate_routes/test/translate_routes_test.rb323
-rwxr-xr-xvendor/plugins/translate_routes/uninstall.rb1
m---------vendor/rails-locales0
99 files changed, 4927 insertions, 280 deletions
diff --git a/.gitignore b/.gitignore
index 75bb8101f..911f019c6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,5 @@
._*
/db/test_structure.sql
moo.txt
+*#*#
+TAGS \ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
index f98b4a514..78f90064f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,9 @@
[submodule "vendor/rails"]
path = vendor/rails
url = https://github.com/rails/rails.git
+[submodule "vendor/rails-locales"]
+ path = vendor/rails-locales
+ url = https://github.com/svenfuchs/rails-i18n.git
+[submodule "vendor/plugins/alavetelitheme"]
+ path = vendor/plugins/alavetelitheme
+ url = https://github.com/sebbacon/alavetelitheme.git \ No newline at end of file
diff --git a/INSTALL.txt b/INSTALL.txt
index e897266fb..2379cdfdd 100644
--- a/INSTALL.txt
+++ b/INSTALL.txt
@@ -40,7 +40,7 @@ code. Run:
git submodule update --init
-to fetch the contents of the submodule s.
+to fetch the contents of the submodules.
2. Configure Database
---------------------
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 9382e077f..91754e2ba 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -12,11 +12,28 @@
class ApplicationController < ActionController::Base
# Standard headers, footers and navigation for whole site
layout "default"
- # set locale
+ include FastGettext::Translation # make functions like _, n_, N_ etc available)
before_filter :set_gettext_locale
+
+ # scrub sensitive parameters from the logs
+ filter_parameter_logging :password
+
+
+ def set_gettext_locale
+ requested_locale = params[:locale] || session[:locale] || cookies[:locale] || request.env['HTTP_ACCEPT_LANGUAGE']
+ session[:locale] = FastGettext.set_locale(requested_locale)
+ end
+
# scrub sensitive parameters from the logs
filter_parameter_logging :password
+ helper_method :site_name, :locale_from_params
+ def site_name
+ # XXX should come from database:
+ site_name = "WhatDoTheyKnow"
+ return site_name
+ end
+
# Help work out which request causes RAM spike.
# http://www.codeweblog.com/rails-to-monitor-the-process-of-memory-leaks-skills/
# This shows the memory use increase of the Ruby process due to the request.
@@ -131,6 +148,16 @@ class ApplicationController < ActionController::Base
f.write(content)
end
end
+
+ # get the local locale
+ def locale_from_params(*args)
+ if params[:show_locale]
+ params[:show_locale]
+ else
+ I18n.locale.to_s
+ end
+ end
+
private
# Check the user is logged in
diff --git a/app/controllers/general_controller.rb b/app/controllers/general_controller.rb
index 21e715424..cf28208a0 100644
--- a/app/controllers/general_controller.rb
+++ b/app/controllers/general_controller.rb
@@ -22,22 +22,7 @@ class GeneralController < ApplicationController
def frontpage
behavior_cache do
# This is too slow
- #@popular_bodies = PublicBody.find(:all, :select => "*, (select count(*) from info_requests where info_requests.public_body_id = public_bodies.id) as c", :order => "c desc", :limit => 32)
-
- # Just hardcode some popular authorities for now
- # ('tgq', 'atbra' is for debugging on Francis's development environment)
- @popular_bodies = PublicBody.find(:all, :conditions => ["url_name in (
- 'bbc',
- 'dwp',
- 'dh',
- 'snh',
- 'royal_mail_group',
- 'mod',
- 'kent_county_council',
- 'wirral_borough_council'
- /* , 'tgq', 'atbra' */
- )"]).sort_by { |pb| pb.url_name }.reverse # just an order that looks better
-
+ @popular_bodies = PublicBody.find(:all, :select => "*, (select count(*) from info_requests where info_requests.public_body_id = public_bodies.id) as c", :order => "c desc", :limit => 32)
# Get some successful requests #
begin
query = 'variety:response (status:successful OR status:partially_successful)'
@@ -168,5 +153,11 @@ class GeneralController < ApplicationController
render :text => "awake\n"
end
+ def custom_css
+ @locale = self.locale_from_params()
+ render(:layout => false, :content_type => 'text/css')
+ end
+
+
end
diff --git a/app/controllers/public_body_controller.rb b/app/controllers/public_body_controller.rb
index 17eba911f..cf64046ea 100644
--- a/app/controllers/public_body_controller.rb
+++ b/app/controllers/public_body_controller.rb
@@ -16,87 +16,96 @@ class PublicBodyController < ApplicationController
return
end
- @public_body = PublicBody.find_by_url_name_with_historic(params[:url_name])
- raise "None found" if @public_body.nil? # XXX proper 404
+ @locale = self.locale_from_params()
+ PublicBody.with_locale(@locale) do
+ @public_body = PublicBody.find_by_url_name_with_historic(params[:url_name])
+ raise "None found" if @public_body.nil? # XXX proper 404
- # If found by historic name, redirect to new name
- redirect_to show_public_body_url(:url_name => @public_body.url_name) if
- @public_body.url_name != params[:url_name]
+ # If found by historic name, redirect to new name
+ redirect_to show_public_body_url(:url_name => @public_body.url_name) if
+ @public_body.url_name != params[:url_name]
- set_last_body(@public_body)
+ set_last_body(@public_body)
- top_url = main_url("/")
- @searched_to_send_request = false
- referrer = request.env['HTTP_REFERER']
- if !referrer.nil? && referrer.match(%r{^#{top_url}search/.*/bodies$})
- @searched_to_send_request = true
- end
+ top_url = main_url("/")
+ @searched_to_send_request = false
+ referrer = request.env['HTTP_REFERER']
+ if !referrer.nil? && referrer.match(%r{^#{top_url}search/.*/bodies$})
+ @searched_to_send_request = true
+ end
- # Use search query for this so can collapse and paginate easily
- # XXX really should just use SQL query here rather than Xapian.
- begin
- @xapian_requests = perform_search([InfoRequestEvent], 'requested_from:' + @public_body.url_name, 'newest', 'request_collapse')
- if (@page > 1)
- @page_desc = " (page " + @page.to_s + ")"
- else
- @page_desc = ""
+ # Use search query for this so can collapse and paginate easily
+ # XXX really should just use SQL query here rather than Xapian.
+ begin
+ @xapian_requests = perform_search([InfoRequestEvent], 'requested_from:' + @public_body.url_name, 'newest', 'request_collapse')
+ if (@page > 1)
+ @page_desc = " (page " + @page.to_s + ")"
+ else
+ @page_desc = ""
+ end
+ rescue
+ @xapian_requests = nil
end
- rescue
- @xapian_requests = nil
- end
- @track_thing = TrackThing.create_track_for_public_body(@public_body)
- @feed_autodetect = [ { :url => do_track_url(@track_thing, 'feed'), :title => @track_thing.params[:title_in_rss], :has_json => true } ]
+ @track_thing = TrackThing.create_track_for_public_body(@public_body)
+ @feed_autodetect = [ { :url => do_track_url(@track_thing, 'feed'), :title => @track_thing.params[:title_in_rss], :has_json => true } ]
- respond_to do |format|
- format.html { @has_json = true }
- format.json { render :json => @public_body.json_for_api }
+ respond_to do |format|
+ format.html { @has_json = true }
+ format.json { render :json => @public_body.json_for_api }
+ end
end
end
def view_email
@public_bodies = PublicBody.find(:all, :conditions => [ "url_name = ?", params[:url_name] ])
@public_body = @public_bodies[0]
-
- if params[:submitted_view_email]
- if verify_recaptcha
- flash.discard(:error)
- render :template => "public_body/view_email"
- return
+ PublicBody.with_locale(self.locale_from_params()) do
+ if params[:submitted_view_email]
+ if verify_recaptcha
+ flash.discard(:error)
+ render :template => "public_body/view_email"
+ return
+ end
+ flash.now[:error] = "There was an error with the words you entered, please try again."
end
- flash.now[:error] = "There was an error with the words you entered, please try again."
+ render :template => "public_body/view_email_captcha"
end
- render :template => "public_body/view_email_captcha"
end
def list
# XXX move some of these tag SQL queries into has_tag_string.rb
@tag = params[:tag]
+ @locale = self.locale_from_params()
+ locale_condition = 'public_body_translations.locale = ?'
if @tag.nil?
@tag = "all"
- conditions = []
+ conditions = [locale_condition, @locale]
elsif @tag == 'other'
category_list = PublicBodyCategories::CATEGORIES.map{|c| "'"+c+"'"}.join(",")
- conditions = ['(select count(*) from has_tag_string_tags where has_tag_string_tags.model_id = public_bodies.id
+ conditions = [locale_condition + ' AND (select count(*) from has_tag_string_tags where has_tag_string_tags.model_id = public_bodies.id
and has_tag_string_tags.model = \'PublicBody\'
- and has_tag_string_tags.name in (' + category_list + ')) = 0']
+ and has_tag_string_tags.name in (' + category_list + ')) = 0', @locale]
elsif @tag.size == 1
@tag.upcase!
- conditions = ['first_letter = ?', @tag]
+ conditions = [locale_condition + ' AND public_body_translations.first_letter = ?', @locale, @tag]
elsif @tag.include?(":")
name, value = HasTagString::HasTagStringTag.split_tag_into_name_value(@tag)
- conditions = ['(select count(*) from has_tag_string_tags where has_tag_string_tags.model_id = public_bodies.id
+ conditions = [locale_condition + ' AND (select count(*) from has_tag_string_tags where has_tag_string_tags.model_id = public_bodies.id
and has_tag_string_tags.model = \'PublicBody\'
- and has_tag_string_tags.name = ? and has_tag_string_tags.value = ?) > 0', name, value]
+ and has_tag_string_tags.name = ? and has_tag_string_tags.value = ?) > 0', @locale, name, value]
else
- conditions = ['(select count(*) from has_tag_string_tags where has_tag_string_tags.model_id = public_bodies.id
+ conditions = [locale_condition + ' AND (select count(*) from has_tag_string_tags where has_tag_string_tags.model_id = public_bodies.id
and has_tag_string_tags.model = \'PublicBody\'
- and has_tag_string_tags.name = ?) > 0', @tag]
+ and has_tag_string_tags.name = ?) > 0', @locale, @tag]
end
- @public_bodies = PublicBody.paginate(
- :order => "public_bodies.name", :page => params[:page], :per_page => 1000, # fit all councils on one page
- :conditions => conditions
+ PublicBody.with_locale(@locale) do
+ @public_bodies = PublicBody.paginate(
+ :order => "public_body_translations.name", :page => params[:page], :per_page => 1000, # fit all councils on one page
+ :conditions => conditions,
+ :joins => :translations
)
+ end
if @tag.size == 1
@description = "beginning with '" + @tag + "'"
else
diff --git a/app/helpers/link_to_helper.rb b/app/helpers/link_to_helper.rb
index 93151ecfe..85913b12e 100644
--- a/app/helpers/link_to_helper.rb
+++ b/app/helpers/link_to_helper.rb
@@ -197,6 +197,12 @@ module LinkToHelper
return date.strftime("%Y").strip
end
+ #I18n locale switcher
+
+ def locale_switcher(locale, params)
+ params['locale'] = locale
+ return url_for(params)
+ end
end
diff --git a/app/models/public_body.rb b/app/models/public_body.rb
index 446ac2334..51d6ea914 100644
--- a/app/models/public_body.rb
+++ b/app/models/public_body.rb
@@ -44,6 +44,9 @@ class PublicBody < ActiveRecord::Base
has_tag_string
+ translates :name, :short_name, :request_email, :url_name, :notes
+ translates :first_letter, :publication_scheme
+
# like find_by_url_name but also search historic url_name if none found
def self.find_by_url_name_with_historic(name)
found = PublicBody.find_all_by_url_name(name)
@@ -67,7 +70,8 @@ class PublicBody < ActiveRecord::Base
# Set the first letter, which is used for faster queries
before_save(:set_first_letter)
def set_first_letter
- self.first_letter = self.name[0,1].upcase
+ # we use a regex to ensure it works with utf-8/multi-byte
+ self.first_letter = self.name.scan(/./mu)[0].upcase
end
def validate
@@ -166,16 +170,21 @@ class PublicBody < ActiveRecord::Base
# When name or short name is changed, also change the url name
def short_name=(short_name)
- write_attribute(:short_name, short_name)
+ globalize.write(self.class.locale || I18n.locale, :short_name, short_name)
+ self[:short_name] = short_name
+ globalize.save_translations!
self.update_url_name
end
def name=(name)
- write_attribute(:name, name)
+ globalize.write(self.class.locale || I18n.locale, :name, name)
+ self[:name] = name
+ globalize.save_translations!
self.update_url_name
end
+
def update_url_name
url_name = MySociety::Format.simplify_url_part(self.short_or_long_name, 'body')
- write_attribute(:url_name, url_name)
+ self.url_name = url_name
end
# Return the short name if present, or else long name
def short_or_long_name
diff --git a/app/views/admin_public_body/_locale_selector.rhtml b/app/views/admin_public_body/_locale_selector.rhtml
new file mode 100644
index 000000000..5ef79f2df
--- /dev/null
+++ b/app/views/admin_public_body/_locale_selector.rhtml
@@ -0,0 +1,10 @@
+<div id="locale_switcher">
+<%= _('Edit language version:') %>
+<% for possible_locale in @locales %>
+ <% if possible_locale == @locale %>
+ <%= possible_locale %>
+ <% else %>
+ <a href="?show_locale=<%=possible_locale%>"><%= possible_locale %></a>
+ <% end %>
+<% end %>
+</div>
diff --git a/app/views/comment/_comment_form.rhtml b/app/views/comment/_comment_form.rhtml
index aae0c4638..f943cf8ad 100644
--- a/app/views/comment/_comment_form.rhtml
+++ b/app/views/comment/_comment_form.rhtml
@@ -6,7 +6,7 @@
<% if !TrackThing.find_by_existing_track(@user, track_thing) && (!@user || @info_request.user != @user) %>
<p>
- <%= check_box_tag 'subscribe_to_request', "1", params[:subscribe_to_request] ? true : false %> <label for="subscribe_to_request">Email me future updates to this request</label>
+ <%= check_box_tag 'subscribe_to_request', "1", params[:subscribe_to_request] ? true : false %> <label for="subscribe_to_request"><%= _('Email me future updates to this request') %></label>
</p>
<% end %>
diff --git a/app/views/general/_before_body_end.rhtml b/app/views/general/_before_body_end.rhtml
new file mode 100644
index 000000000..8d7ebeeb5
--- /dev/null
+++ b/app/views/general/_before_body_end.rhtml
@@ -0,0 +1,16 @@
+<% if MySociety::Config.get("DOMAIN", '127.0.0.1:3000') == 'www.whatdotheyknow.com' %>
+<!-- Piwik -->
+<script type="text/javascript">
+var pkBaseURL = (("https:" == document.location.protocol) ? "https://piwik.mysociety.org/" : "http://piwik.mysociety.org/");
+document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
+</script><script type="text/javascript">
+try {
+var piwikTracker = Piwik.getTracker(pkBaseURL + "piwik.php", 4);
+piwikTracker.trackPageView();
+piwikTracker.enableLinkTracking();
+} catch( err ) {}
+</script><noscript><p><img src="http://piwik.mysociety.org/piwik.php?idsite=4" style="border:0" alt=""/></p></noscript>
+<!-- End Piwik Tag -->
+<% end %>
+
+
diff --git a/app/views/general/_credits.rhtml b/app/views/general/_credits.rhtml
new file mode 100644
index 000000000..a2f7a9cb2
--- /dev/null
+++ b/app/views/general/_credits.rhtml
@@ -0,0 +1,5 @@
+|
+ Built by <a href="http://www.mysociety.org/">mySociety</a> ...
+ <a href="/help/credits#helpus">and you</a>
+ |
+ Dedicated to <a href="http://mk.ucant.org/archives/000129.html">Chris Lightfoot</a>
diff --git a/app/views/general/_locale_switcher.rhtml b/app/views/general/_locale_switcher.rhtml
new file mode 100644
index 000000000..4f01a4d13
--- /dev/null
+++ b/app/views/general/_locale_switcher.rhtml
@@ -0,0 +1,12 @@
+ <% if FastGettext.default_available_locales.length > 1 %>
+ <div id="user_locale_switcher">
+ Language:
+ <% for possible_locale in FastGettext.default_available_locales %>
+ <% if possible_locale == I18n.locale.to_s %>
+ <%= possible_locale %>
+ <% else %>
+ <a href="<%= locale_switcher(possible_locale, params) %>"><%= possible_locale %></a>
+ <% end %>
+ <% end %>
+ </div>
+ <% end %>
diff --git a/app/views/general/_orglink.rhtml b/app/views/general/_orglink.rhtml
new file mode 100644
index 000000000..551b18646
--- /dev/null
+++ b/app/views/general/_orglink.rhtml
@@ -0,0 +1,2 @@
+<%-# Put the link to your organisation here, or leave blank -%>
+<a href="http://www.mysociety.org">a site by mysociety.org</a>
diff --git a/app/views/general/custom_css.rhtml b/app/views/general/custom_css.rhtml
new file mode 100644
index 000000000..0def82ed0
--- /dev/null
+++ b/app/views/general/custom_css.rhtml
@@ -0,0 +1 @@
+// this should be overridden in a local "theme" plugin
diff --git a/app/views/general/frontpage.rhtml b/app/views/general/frontpage.rhtml
index 51bf55e34..276ac70a7 100644
--- a/app/views/general/frontpage.rhtml
+++ b/app/views/general/frontpage.rhtml
@@ -1,25 +1,28 @@
<% view_cache :ttl => 5.minutes do %>
<div id="frontpage_search">
- <h1>Make or explore Freedom of Information requests</h1>
+ <h1><%= _('Make or explore Freedom of Information requests') %></h1>
<% form_tag({:action => "search_redirect"}, {:id => "search_form"}) do %>
<p>
- First, type in the <strong>name of the UK public authority</strong> you'd
+ <%= _('First, type in the <strong>name of the UK public authority</strong> you\'d
<br>like information from. <strong>By law, they have to respond</strong>
- (<a href="/help/about">why?</a>).
+ (<a href="%s">why?</a>).') % help_about_url %>
<br>
<br>
<%= text_field_tag 'query', params[:query], { :size => 30 } %>
<%= hidden_field_tag 'bodies', 1 %>
- <%= submit_tag "Search" %>
+ <%= submit_tag _('Search') %>
<br>
- e.g. <%=link_to 'Liverpool', search_url('liverpool', 'bodies')%>, <%=link_to 'MRSA', search_url('mrsa', 'bodies')%>, <%=link_to 'Treasury', search_url('treasury', 'bodies')%>
+ <%= _('e.g.') %>
+ <% @popular_bodies.each_with_index do |body, i| %>
+ <%=link_to body.name, search_url(body.name, 'bodies')%><% if i < 2 %>, <% else %>. <% break %><% end %>
+ <% end %>
<br>
<br>
- OR, <strong>search</strong> for information others have requested using WhatDoTheyKnow.com
+ <%= _('OR, <strong>search</strong> for information others have requested using {{site_name}}', :site_name => site_name) %>
</p>
<% end %>
</div>
@@ -27,15 +30,15 @@
<div id="frontpage_examples">
<% if @popular_bodies.size > 0 %>
<div id="examples_0">
- <ul>
+ <ul>
<% for popular_body in @popular_bodies %>
<li><%=public_body_link(popular_body)%>
- <%=h popular_body.info_requests.count%> requests
+ <%= n_('%d request', '%d requests', popular_body.info_requests.count) % popular_body.info_requests.count %>
</li>
<% end%>
</ul>
<p><strong>
- <%= link_to "More authorities...", list_public_bodies_default %>
+ <%= link_to _('More authorities...'), list_public_bodies_default %>
</strong></p>
</div>
<% end %>
@@ -45,11 +48,11 @@
<ul>
<% for event in @successful_request_events %>
<li><%=link_to h(excerpt(event.info_request.title, "", 30)), request_url(event.info_request)%>
- <%=h time_ago_in_words(event.described_at).gsub("about ", "") %> ago
+ <%= _('{{length_of_time}} ago', :length_of_time => time_ago_in_words(event.described_at)) %>
</li>
<% end %>
</ul>
- <p><strong><a href="/list/successful">More successful requests...</a></strong></p>
+ <p><strong><%=link_to _('More successful requests...'), request_list_successful_url %></strong></p>
</div>
<% end %>
</div>
diff --git a/app/views/general/search.rhtml b/app/views/general/search.rhtml
index 29ce73d5c..876d54270 100644
--- a/app/views/general/search.rhtml
+++ b/app/views/general/search.rhtml
@@ -1,21 +1,20 @@
<% @show_tips = @xapian_requests.nil? || (@total_hits == 0) %>
<% if @query.nil? %>
- <% @title = "Search Freedom of Information requests, public authorities and users" %>
+ <% @title = _("Search Freedom of Information requests, public authorities and users") %>
<h1><%=@title%></h1>
<% elsif @total_hits == 0 %>
- <% @title = "Nothing found for '" + h(@query) + "'" %>
+ <%= _("Nothing found for '{{search_terms}}'", :search_terms => h(@query)) %>
<% else %>
- <% @title = "Results page " + @page.to_s %>
+ <% @title = _("Results page {{page_number}}", :page_number => @page.to_s) %>
<% end%>
<% @include_request_link_in_authority_listing = true %>
<% if @bodies && (@page == 1 || @xapian_bodies.results.size > 0) %>
<div id="stepwise_instructions">
- <p><strong>Next, select the public authority you'd like to make the request from.</strong></p>
- <p>Can't find it? <%= link_to "Browse all", list_public_bodies_default %> or
- <a href="/help/requesting#missing_body">ask us to add it</a>.</p>
+ <p><strong><%=_("Next, select the public authority you'd like to make the request from.") %></strong></p>
+ <p><% _('Can\'t find it? <a href="%s">Browse all</a> or <a href="%s">ask us to add it</a>.') % [list_public_bodies_default, "#{help_requesting_path}#missing_body"] %></p>
<p>
</div>
<% end %>
@@ -27,30 +26,31 @@
<% if @bodies %>
<%= hidden_field_tag 'bodies', 1 %>
<% end %>
- <%= submit_tag "Search" %>
+ <%= submit_tag _("Search") %>
<% if not @show_tips %>
- &nbsp;&nbsp;<a href="/search">Advanced search tips</a>
+ &nbsp;&nbsp;<%= link_to _('Advanced search tips'), search_redirect_path %>
<% end %>
</p>
<% end %>
<% if !@query.nil? %>
<p>
- <%=link_to_unless @sortby == 'relevant', "Show most relevant results first", search_url(@query, 'relevant') %>
+ <%=link_to_unless @sortby == 'relevant', _("Show most relevant results first"), search_url(@query, 'relevant') %>
|
- <%=link_to_unless @sortby == 'newest', "Newest results first", search_url(@query, 'newest') %>
+ <%=link_to_unless @sortby == 'newest', _("Newest results first"), search_url(@query, 'newest') %>
<% if @sortby == 'described' %>
- | Recently described results first
+ | <%= _('Recently described results first') %>
<% end %>
</p>
<% end %>
<% if @bodies && !@query.nil? && @xapian_bodies.results.size == 0 && @page == 1 %>
- <h1>No public authorities found</h1>
+ <h1><%= _('No public authorities found') %></h1>
<% if @spelling_correction %>
- <p id="did_you_mean">Did you mean: <%= search_link(@spelling_correction, @postfix) %></p>
+ <p id="did_you_mean"><%= _('Did you mean: {{correction}}',
+ :correction => search_link(@spelling_correction, @postfix)) %></p>
<% end %>
- <p><%=link_to "Browse all", list_public_bodies_default %> or <a href="/help/requesting#missing_body">ask us to add one</a>.</p>
+ <p><%= _('<a href="%s">Browse all</a> or <a href="%s">ask us to add one</a>.') % [list_public_bodies_default, help_requesting_path + '#missing_body'] %></p>
<% end %>
<% if @total_hits == 0 %>
@@ -59,7 +59,7 @@
<% if not @query.nil? %>
<% if @spelling_correction %>
- <p id="did_you_mean">Did you mean: <%= search_link(@spelling_correction, @postfix) %></p>
+ <p id="did_you_mean"><%= _('Did you mean: {{correction}}', :correction => search_link(@spelling_correction, @postfix)) %></p>
<% end %>
<% if (!@bodies || @xapian_requests.results.size == 0) && @track_thing && (@xapian_bodies.results.size > 0 || @xapian_users.results.size > 0 || @total_hits == 0)%>
@@ -67,7 +67,7 @@
<% end %>
<% if @xapian_bodies.results.size > 0 %>
- <h1><%= "Public authorities " + ((@page-1)*@bodies_per_page+1).to_s + "-" + [@page*@bodies_per_page, @xapian_bodies.matches_estimated].min.to_s + " of " + @xapian_bodies.matches_estimated.to_s + " for '" + h(@query) + "'" %></h1>
+ <h1><%= _('Public authorities {{start_count}} to {{end_count}} of {{total_count}} for {{user_search_query}}', :start_count => ((@page-1)*@bodies_per_page+1).to_s, :end_count => [@page*@bodies_per_page, @xapian_bodies.matches_estimated].min.to_s, :total_count => @xapian_bodies.matches_estimated.to_s, :user_search_query => h(@query)) %></h1>
<% for result in @xapian_bodies.results %>
<%= render :partial => 'public_body/body_listing_single', :locals => { :public_body => result[:model] } %>
@@ -77,7 +77,7 @@
<% end %>
<% if @xapian_users.results.size > 0 %>
- <h1><%= "People " + ((@page-1)*@users_per_page+1).to_s + "-" + [@page*@users_per_page, @xapian_users.matches_estimated].min.to_s + " of " + @xapian_users.matches_estimated.to_s + " for '" + h(@query) + "'" %></h1>
+ <h1><%= _("People {{start_count}} to {{end_count}} of {{total_count}} for {{user_search_query}}", :start_count => ((@page-1)*@users_per_page+1).to_s, :end_count => [@page*@users_per_page, @xapian_users.matches_estimated].min.to_s, :total_count => @xapian_users.matches_estimated.to_s, :user_search_query => h(@query)) %></h1>
<% for result in @xapian_users.results %>
<%= render :partial => 'user/user_listing_single', :locals => { :display_user => result[:model] } %>
@@ -87,7 +87,7 @@
<% end %>
<% if @xapian_requests.results.size > 0 %>
- <h1><%= "FOI requests " + ((@page-1)*@requests_per_page+1).to_s + "-" + [@page*@requests_per_page, @xapian_requests.matches_estimated].min.to_s + " of " + @xapian_requests.matches_estimated.to_s + " for '" + h(@query) + "'" %></h1>
+ <h1><%= _("FOI requests {{start_count}} to {{end_count}} of {{total_count}} for {{user_search_query}}", :start_count => ((@page-1)*@requests_per_page+1).to_s, :end_count => [@page*@requests_per_page, @xapian_requests.matches_estimated].min.to_s, :total_count => @xapian_requests.matches_estimated.to_s, :user_search_query => h(@query)) %></h1>
<% if @track_thing %>
<%= render :partial => 'track/tracking_links', :locals => { :track_thing => @track_thing, :own_request => false, :location => 'main' } %>
@@ -106,27 +106,27 @@
<% end %>
<% if @show_tips %>
- <h2>Advanced search tips</h2>
+ <h2><%= _("Advanced search tips")%></h2>
<ul>
- <li>Enter words that you want to find separated by spaces, e.g. <strong><%=search_link('climbing lane')%></strong></li>
- <li>Use OR (in capital letters) where you don't mind which word, e.g. <strong><%=search_link('commons OR lords')%></strong>
- <li>Use quotes when you want to find an exact phrase, e.g. <strong><%=search_link('"Liverpool City Council"')%></strong>
- <li><strong>status:</strong> to select based on the status or historical status of the request, see the <a href="#statuses">table of statuses</a> below.
- <li><strong>variety:</strong> to select type of thing to search for, see the <a href="#varieties">table of varieties</a> below.
- <li><strong><%=search_link('requested_from:home_office')%></strong> to search requests from the <%= link_to "Home Office", show_public_body_url(:url_name => 'home_office') %>, typing the name as in the URL.
- <li><strong><%=search_link('requested_by:julian_todd')%></strong> to search requests made by <%= link_to "Julian Todd", show_user_url(:url_name => 'julian_todd') %>, typing the name as in the URL.
- <li><strong><%=search_link('commented_by:tony_bowden')%></strong> to search annotations made by <%= link_to "Tony Bowden", show_user_url(:url_name => 'tony_bowden') %>, typing the name as in the URL.
- <li><strong>request:</strong> to restrict to a specific request, typing the title as in the URL.
- <li><strong><%=search_link('filetype:pdf')%></strong> to find all responses with PDF attachments. Or try these: <%= IncomingMessage.get_all_file_extentions%>.
- <li>Type <strong><%=search_link('01/01/2008..14/01/2008')%></strong> to only show things that happened in the first two weeks of January.
- <li><strong><%=search_link('tag:charity')%></strong> to find all public bodies or requests with a given tag. You can include multiple tags,
- and tag values, e.g. <%=search_link('tag:openlylocal AND tag:financial_transaction:335633')%>. Note that by default any of the tags
- can be present, you have to put AND explicitly if you only want results them all present.
- <li>Read about <a href="http://www.xapian.org/docs/queryparser.html">advanced search operators</a>, such as proximity and wildcards.
+ <li><%= _("Enter words that you want to find separated by spaces, e.g. <strong>climbing lane</strong>") %></li>
+ <li><%= _('Use OR (in capital letters) where you don\'t mind which word, e.g. <strong><code>commons OR lords</code></strong>') %>
+ <li><%= _('Use quotes when you want to find an exact phrase, e.g. <strong><code>"Liverpool City Council"</code></strong>') %></li>
+ <li><%= _('<strong><code>status:</code></strong> to select based on the status or historical status of the request, see the <a href="%s">table of statuses</a> below.') % "#statuses" %></li>
+ <li><%= _('<strong><code>variety:</code></strong> to select type of thing to search for, see the <a href="%s">table of varieties</a> below.') % "#varieties" %></li>
+ <li><%= _('<strong><code>requested_from:home_office</code></strong> to search requests from the Home Office, typing the name as in the URL.')%></li>
+ <li><%= _('<strong><code>requested_by:julian_todd</code></strong> to search requests made by Julian Todd, typing the name as in the URL.') %></li>
+ <li><%= _('<strong><code>commented_by:tony_bowden</code></strong> to search annotations made by Tony Bowden, typing the name as in the URL.')%></li>
+ <li><%= _('<strong><code>request:</code></strong> to restrict to a specific request, typing the title as in the URL.')%>
+ <li><%= _('<strong><code>filetype:pdf</code></strong> to find all responses with PDF attachments. Or try these: <code>{{list_of_file_extensions}}</code>', :list_of_file_extensions => IncomingMessage.get_all_file_extentions)%></li>
+ <li><%= _('Type <strong><code>01/01/2008..14/01/2008</code></strong> to only show things that happened in the first two weeks of January.')%></li>
+ <li><%= _('<strong><code>tag:charity</code></strong> to find all public bodies or requests with a given tag. You can include multiple tags,
+ and tag values, e.g. <code>tag:openlylocal AND tag:financial_transaction:335633</code>. Note that by default any of the tags
+ can be present, you have to put <code>AND</code> explicitly if you only want results them all present.')%></li>
+ <li><%= _('Read about <a href="%s">advanced search operators</a>, such as proximity and wildcards.') % "http://www.xapian.org/docs/queryparser.html" %></li>
</ul>
- <h2 id="statuses">Table of statuses</h2>
-
+ <h2 id="statuses"><%= _('Table of statuses') %></h2>
+ <h3>XXX this should be automatically generated</h3>
<table class="status_table">
<tr><td><strong><%=search_link('status:waiting_response')%></strong></td><td> Waiting for the public authority to reply </td></tr>
<tr><td><strong><%=search_link('status:not_held')%></strong></td><td> The public authority does not have the information requested </td></tr>
diff --git a/app/views/help/about.es.rhtml b/app/views/help/about.es.rhtml
new file mode 100644
index 000000000..721a582aa
--- /dev/null
+++ b/app/views/help/about.es.rhtml
@@ -0,0 +1,10 @@
+<% @title = "Sobre" %>
+
+<%= render :partial => 'sidebar' %>
+
+<h1>¡Bonjiorno amis!</h1>
+
+<p>Esta sito tu aidare a faire los requesti a la governmenti Seblano</p>
+
+<div id="hash_link_padding"></div>
+
diff --git a/app/views/layouts/admin.rhtml b/app/views/layouts/admin.rhtml
index 426a01cf5..a209715e1 100644
--- a/app/views/layouts/admin.rhtml
+++ b/app/views/layouts/admin.rhtml
@@ -9,17 +9,18 @@
<p>
<strong><%= link_to 'WhatDoTheyKnow', main_url('/') %> admin:</strong>
- <%= link_to 'Summary', admin_url('') %>
- | <%= link_to 'Timeline', admin_url('timeline') %>
- | <%= link_to 'Stats', admin_url('stats') %>
- | <%= link_to 'Debug', admin_url('debug') %>
+ <%= link_to 'Summary', admin_general_index_path %>
+ | <%= link_to 'Timeline', admin_timeline_path %>
+ | <%= link_to 'Stats', admin_stats_path %>
+ | <%= link_to 'Debug', admin_debug_path %>
| <%= link_to 'Wiki', "https://secure.mysociety.org/intranet/ProductionSites/WhatDoTheyKnow/WebHome" %>
<strong>View:</strong>
- <%= link_to 'Authorities', admin_url('body/list') %>
- | <%= link_to 'Requests', admin_url('request/list') %>
- | <%= link_to 'Users', admin_url('user/list') %>
- | <%= link_to 'Tracks', admin_url('track/list') %>
+ <%= link_to 'Authorities', admin_body_list_path %>
+ | <%= link_to 'Requests', admin_request_list_path %>
+ | <%= link_to 'Users', admin_user_list_path %>
+ | <%= link_to 'Tracks', admin_track_list_path %>
</p>
+ <%= render :partial => 'general/locale_switcher' %>
<% if flash[:error] %>
<p id="error"><%= flash[:error] %></p>
diff --git a/app/views/layouts/default.rhtml b/app/views/layouts/default.rhtml
index 606203f06..be302103a 100644
--- a/app/views/layouts/default.rhtml
+++ b/app/views/layouts/default.rhtml
@@ -1,5 +1,5 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html lang="en-gb">
+<html lang="<%= I18n.locale %>">
<head>
<script type="text/javascript" src="/jslib/spell/spellChecker.js"></script>
@@ -12,9 +12,9 @@
<title>
<% if @title %>
- <%=@title%> - WhatDoTheyKnow
+ <%=@title%> - <%= site_name %>
<% else %>
- WhatDoTheyKnow - make and browse Freedom of Information (FOI) requests
+ <%= site_name %> - <%= _('Make and browse Freedom of Information (FOI) requests') %>
<% end %>
</title>
@@ -23,7 +23,12 @@
<%= stylesheet_link_tag 'main', :title => "Main", :rel => "stylesheet" %>
<!--[if LT IE 7]>
<style type="text/css">@import url("/stylesheets/ie6.css");</style>
- <![endif]-->
+ <![endif]-->
+ <!--[if LT IE 7]>
+ <style type="text/css">@import url("/stylesheets/ie6-custom.css");</style>
+ <![endif]-->
+ <%= stylesheet_link_tag 'main-custom', :title => "Main", :rel => "stylesheet" %>
+ <link href="http://127.0.0.1:3000/custom.css" media="screen" rel="stylesheet" type="text/css">
<% if @feed_autodetect %>
<% for feed in @feed_autodetect %>
@@ -68,33 +73,7 @@
=begin
<div id="everypage" class="jshide">
<p style="float:right"><a href="#top" onclick="$.cookie('seen_foi2', 1, { expires: 7, path: '/' }); $('#everypage').hide('slow'); return false;">Close</a></p>
- <h2>Blimey. It looks like the Internets won &ndash; <small>a message from WhatDoTheyKnow</small></h2>
- <p>Sorry to interrupt, but we thought you&rsquo;d like to know that <strong>you won</strong>!
- <p>On the 16th of May 2008 the High Court ruled that MPs&rsquo; expenses must be published under the Freedom of Information Act.
-
- <p>Tomorrow, MPs <strong>were</strong> going to vote on changing the law to keep their expenses secret after all,
- just before publication was due and after spending nearly a million of your pounds and seven months
- compiling the data.
-
- <p>However, after a <strong>tremendous response</strong> from you, with over 7,000 members
- on our Facebook group, 4,000 messages sent to MPs, help from
-
- <a href="http://twitter.com/stephenfry/statuses/1136046150">Stephen Fry</a>, and a helpful
- <a href="http://www.publications.parliament.uk/pa/ld200809/ldselect/ldmerit/16/1603.htm">4th Report of the House of Lords
- Merits of Statutory Instruments Committee</a>,
- it appears that the vote has been cancelled &ndash;
- <a href="http://www.guardian.co.uk/politics/2009/jan/21/mps-expenses">Guardian</a>,
- <a href="http://www.timesonline.co.uk/tol/news/politics/article5559704.ece">Times</a>,
- <a href="http://news.bbc.co.uk/1/hi/uk_politics/7842402.stm">BBC</a>.
-
- <p>As President Obama said in his inauguration speech: <em>&ldquo;And
- those of us who manage the public&rsquo;s dollars will be held to account &ndash; to
- spend wisely, reform bad habits, and do our business in the light of day &ndash;
-
- because only then can we restore the vital trust between a people and their
- government.&rdquo;</em></p>
-
- <p>Read <a href="http://www.mysociety.org/2009/01/21/blimey-it-looks-like-the-internets-won/">our victory blog post</a>. :-)
+ [ message goes here ]
<p style="text-align: right"><a href="#top" onclick="$.cookie('seen_foi2', 1, { expires: 7, path: '/' }); $('#everypage').hide('slow'); return false;">Close</a></p>
</div>
=end
@@ -104,41 +83,45 @@
</div>
<div id="header">
<h1>
- <a href="/">WhatDoTheyKnow?</a>
+ <%= link_to site_name, frontpage_url %>
</h1>
<div id="tagline">
- Make and explore Freedom of Information requests
+ <%= _('Make and explore Freedom of Information requests') %>
</div>
+ <%= render :partial => 'general/locale_switcher' %>
+
</div>
- <div id="mysoclogo">
- <a href="http://www.mysociety.org">a site by mysociety.org</a>
+ <div id="orglogo">
+ <%= render :partial => 'general/orglink' %>
</div>
+
<div id="navigation_search">
<% form_tag({:controller => "general", :action => "search_redirect"}, {:id => "navigation_search_form"}) do %>
<p>
<%= text_field_tag 'query', params[:query], { :size => 40, :id => "navigation_search_query" } %>
- <%= submit_tag "Search" %>
+ <%= submit_tag _("Search") %>
</p>
<% end %>
</div>
<div id="topnav">
<ul id="navigation">
- <li><%= link_to "Make request", frontpage_url %></li>
- <li><%= link_to "View requests", request_list_url(:view => 'successful') %></li>
- <li><%= link_to "View authorities", list_public_bodies_default %></li>
+ <li><%= link_to _("Make request"), frontpage_url %></li>
+ <li><%= link_to _("View requests"), request_list_successful_url %></li>
+ <li><%= link_to _("View authorities"), list_public_bodies_default %></li>
<% if @user %>
- <li><%=link_to "My requests", user_url(@user) %></li>
+ <li><%=link_to _("My requests"), user_url(@user) %></li>
<% end %>
- <li><%= link_to "Read blog", blog_url %></li>
- <li><%= link_to "Help", about_url %></li>
+ <li><%= link_to _("Read blog"), blog_url %></li>
+ <li><%= link_to _("Help"), help_about_url %></li>
</ul>
<% if not (controller.action_name == 'signin' or controller.action_name == 'signup') %>
<div id="logged_in_bar">
<% if @user %>
- Hello, <%=h(@user.name)%>!
- (<%= link_to "Sign out", signout_url(:r => request.request_uri) %>)
+ <%= _('Hello, {{username}}!', :username => h(@user.name))%>
+ (<%= link_to _("Sign out"), signout_url(:r => request.request_uri) %>)
<% else %>
- Hello! (<%= link_to "Sign in or sign up", signin_url(:r => request.request_uri) %>)
+ <%= _('Hello!') %>
+ (<%= link_to _("Sign in or sign up"), signin_url(:r => request.request_uri) %>)
<% end %>
</div>
<% end %>
@@ -161,28 +144,11 @@
</div>
<div id="footer">
- <a href="/help/contact">Contact WhatDoTheyKnow</a>
- |
- Built by <a href="http://www.mysociety.org/">mySociety</a> ...
- <a href="/help/credits#helpus">and you</a>
- |
- Dedicated to <a href="http://mk.ucant.org/archives/000129.html">Chris Lightfoot</a>
+ <%= link_to _("Contact {{site_name}}", :site_name => site_name), help_contact_url %>
+ <%= render :partial => 'general/credits' %>
</div>
-<% if MySociety::Config.get("DOMAIN", '127.0.0.1:3000') == 'www.whatdotheyknow.com' %>
-<!-- Piwik -->
-<script type="text/javascript">
-var pkBaseURL = (("https:" == document.location.protocol) ? "https://piwik.mysociety.org/" : "http://piwik.mysociety.org/");
-document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
-</script><script type="text/javascript">
-try {
-var piwikTracker = Piwik.getTracker(pkBaseURL + "piwik.php", 4);
-piwikTracker.trackPageView();
-piwikTracker.enableLinkTracking();
-} catch( err ) {}
-</script><noscript><p><img src="http://piwik.mysociety.org/piwik.php?idsite=4" style="border:0" alt=""/></p></noscript>
-<!-- End Piwik Tag -->
-<% end %>
+ <%= render :partial => 'general/before_body_end' %>
</body>
</html>
diff --git a/app/views/public_body/show.rhtml b/app/views/public_body/show.rhtml
index c1deea762..8b56d68c0 100644
--- a/app/views/public_body/show.rhtml
+++ b/app/views/public_body/show.rhtml
@@ -1,33 +1,34 @@
<% @title = h(@public_body.name) + " - view and make Freedom of Information requests" %>
<div id="request_sidebar">
- <h2>Track this authority</h2>
+ <h2><%= _('Track this authority')%></h2>
<%= render :partial => 'track/tracking_links', :locals => { :track_thing => @track_thing, :own_request => false, :location => 'sidebar' } %>
- <h2>More about this authority</h2>
+ <h2><%= _('More about this authority')%></h2>
<% if !@public_body.calculated_home_page.nil? %>
- <%= link_to "Home page of authority", @public_body.calculated_home_page %><br>
+ <%= link_to _('Home page of authority'), @public_body.calculated_home_page %><br>
<% end %>
<% if !@public_body.publication_scheme.empty? %>
- <%= link_to "Publication scheme", @public_body.publication_scheme %><br>
+ <%= link_to _('Publication scheme'), @public_body.publication_scheme %><br>
<% end %>
<% if @public_body.has_tag?("charity") %>
<% for tag_value in @public_body.get_tag_values("charity") %>
+ XXX UK-specific
<% if tag_value.match(/^SC/) %>
- <%= link_to "Charity registration", "http://www.oscr.org.uk/CharityIndexDetails.aspx?id=" + tag_value %><br>
+ <%= link_to _('Charity registration'), "http://www.oscr.org.uk/CharityIndexDetails.aspx?id=" + tag_value %><br>
<% else %>
- <%= link_to "Charity registration", "http://www.charity-commission.gov.uk/SHOWCHARITY/RegisterOfCharities/CharityFramework.aspx?RegisteredCharityNumber=" + tag_value %><br>
+ <%= link_to _('Charity registration'), "http://www.charity-commission.gov.uk/SHOWCHARITY/RegisterOfCharities/CharityFramework.aspx?RegisteredCharityNumber=" + tag_value %><br>
<% end %>
<% end %>
<% end %>
- <%= link_to "View FOI email address", view_public_body_email_url(@public_body.url_name) %><br>
+ <%= link_to _('View FOI email address'), view_public_body_email_url(@public_body.url_name) %><br>
</div>
<h1><%=h(@public_body.name)%></h1>
<p class="subtitle">
-<%=@public_body.type_of_authority(true)%> in the UK<% if not @public_body.short_name.empty? %>, also called <%= h(@public_body.short_name) %><% end %>
+<%=@public_body.type_of_authority(true)%><% if not @public_body.short_name.empty? %>, <%= _('also called {{public_body_short_name}}', :public_body_short_name => h(@public_body.short_name))%><% end %>
<% if !@user.nil? && @user.admin_page_links? %>
-(<%= link_to "admin", public_body_admin_url(@public_body) %>)
+(<%= link_to _("admin"), public_body_admin_url(@public_body) %>)
<% end %>
</p>
@@ -36,51 +37,48 @@
<% end %>
<% if @public_body.eir_only? %>
- <p>You can only request information about the environment from this authority.</p>
+ <p><%= _('You can only request information about the environment from this authority.')%></p>
<% end %>
<div id="stepwise_make_request">
<strong>
<% if @public_body.is_requestable? || @public_body.not_requestable_reason == 'bad_contact' %>
- <% make = 'Make' %>
- <% if @searched_to_send_request %>
- Next,
- <% make = 'make' %>
- <% end %>
<% if @public_body.eir_only? %>
- <%= link_to make + " a new Environmental Information request", new_request_to_body_url(:url_name => @public_body.url_name)%>
+ <%= link_to "Make a new Environmental Information request", new_request_to_body_url(:url_name => @public_body.url_name)%> to <%= h(@public_body.name) %>
+
<% else %>
- <%= link_to make + " a new Freedom of Information request", new_request_to_body_url(:url_name => @public_body.url_name)%>
+ <%= _('<a href="%s">Make a new Freedom of Information request</a> to {{public_body_name}}',
+ :public_body_name => h(@public_body.name)) % new_request_to_body_url(:url_name => @public_body.url_name)%>
<% end %>
- to <%= h(@public_body.name) %>
<% elsif @public_body.has_notes? %>
<%= @public_body.notes_as_html %>
<% elsif @public_body.not_requestable_reason == 'not_apply' %>
- Freedom of Information law does not apply to this authority, so you cannot make
- a request to it.
+ <%= _('Freedom of Information law does not apply to this authority, so you cannot make
+ a request to it.')%>
<% elsif @public_body.not_requestable_reason == 'defunct' %>
- This authority no longer exists, so you cannot make a request to it.
+ <%= _('This authority no longer exists, so you cannot make a request to it.')%>
<% else %>
- For an unknown reason, it is not possible to make a request to this authority.
+ <%= _('For an unknown reason, it is not possible to make a request to this authority.')%>
<% end %>
</strong>
</div>
<% if !@xapian_requests.nil? %>
- <% if @xapian_requests.results.empty? %>
+ <% if @xapian_requests.results.empty? %>
<% if @public_body.eir_only? %>
<h2>Environmental Information Regulations requests made using this site</h2>
+ <h4>XXX this section needs localising re EIR as these are specific to UK law</h4>
<p>Nobody has made any Environmental Information Regulations requests to <%=h(@public_body.name)%> using this site yet.</p>
<% else %>
- <h2>Freedom of Information requests made using this site</h2>
- <p>Nobody has made any Freedom of Information requests to <%=h(@public_body.name)%> using this site yet.</p>
+ <h2> <%= _('Freedom of Information requests made using this site')%></h2>
+ <p> <%= _('Nobody has made any Freedom of Information requests to {{public_body_name}} using this site yet.', :public_body_name => h(@public_body.name))%></p>
<% end %>
<% else %>
<h2>
<% if @public_body.eir_only? %>
<%=pluralize(@public_body.info_requests.size, "Environmental Information Regulations request") %> made using this site
<% else %>
- <%=pluralize(@public_body.info_requests.size, "Freedom of Information request") %> made using this site
+ <%= n_('%d Freedom of Information request', '%d Freedom of Information requests', @public_body.info_requests.size) % @public_body.info_requests.size %> made using this site
<% end %>
<%= @page_desc %>
</h2>
@@ -91,15 +89,15 @@
<%= will_paginate WillPaginate::Collection.new(@page, @per_page, @public_body.info_requests.size) %>
- <p>Only requests made using WhatDoTheyKnow.com are shown.</p>
+ <p> <%= _('Only requests made using {{site_name}} are shown.', :site_name => site_name) %></p>
<% end %>
<% else %>
<% if @public_body.eir_only? %>
<h2>Environmental Information Regulations requests made</h2>
<% else %>
- <h2>Freedom of Information requests made</h2>
+ <h2> <%= _('Freedom of Information requests made')%></h2>
<% end %>
- <p>The search index is currently offline, so we can't show the Freedom of Information requests that have been made to this authority.</p>
+ <p> <%= _('The search index is currently offline, so we can\'t show the Freedom of Information requests that have been made to this authority.')%></p>
<% end %>
diff --git a/app/views/request/list.rhtml b/app/views/request/list.rhtml
index 222bd938d..90e5f4605 100644
--- a/app/views/request/list.rhtml
+++ b/app/views/request/list.rhtml
@@ -1,12 +1,12 @@
<div id="list_sidebar">
<h1>Show only...</h1>
<ul>
-<% for view, description in [
- ['successful', "Successful responses"],
- ['recent', "Recently sent requests"]
+<% for view, description, target in [
+ ['successful', "Successful responses", request_list_successful_url(:view => 'successful')],
+ ['recent', "Recently sent requests", request_list_recent_url(:view => 'recent')]
] %>
-<li>
- <%= link_to_unless (@view == view), description, request_list_url(:view => view) %>
+<li>
+ <%= link_to_unless (@view == view), description, target %>
</li>
<% end %>
</ul>
diff --git a/config/environment.rb b/config/environment.rb
index 4f72d030b..a3c93db53 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -6,7 +6,7 @@
# ENV['RAILS_ENV'] ||= 'production'
# Specifies gem version of Rails to use when vendor/rails is not present
-RAILS_GEM_VERSION = '2.3.11' unless defined? RAILS_GEM_VERSION
+RAILS_GEM_VERSION = '2.3.2' unless defined? RAILS_GEM_VERSION
# Bootstrap the Rails environment, frameworks, and default configuration
require File.join(File.dirname(__FILE__), 'boot')
@@ -17,8 +17,9 @@ $:.push(File.join(File.dirname(__FILE__), '../commonlib/rblib'))
# (type "git submodule update --init" in the whatdotheyknow directory)
# ruby-ole and ruby-msg. We use a custom ruby-msg to avoid a name conflict
-$:.unshift(File.join(File.dirname(__FILE__), '../commonlib/rblib/ruby-ole/lib'))
+$:.unshift(File.join(File.dirname(__FILE__), '../vendor/ruby-ole/lib'))
$:.unshift(File.join(File.dirname(__FILE__), '../vendor/ruby-msg/lib'))
+$:.unshift(File.join(File.dirname(__FILE__), '../vendor/plugins/globalize2/lib'))
require 'memcache'
@@ -56,13 +57,13 @@ Rails::Initializer.run do |config|
config.gem 'rspec', :lib => false, :version => '1.3.1'
config.gem 'rspec-rails', :lib => false, :version => '1.3.3'
config.gem 'will_paginate', :version => '~> 2.3.11', :source => 'http://gemcutter.org'
-
+ #GettextI18nRails.translations_are_html_safe = true
# Your secret key for verifying cookie session data integrity.
# If you change this key, all old sessions will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
config.action_controller.session = {
- :key => '_wdtk_cookie_session',
+ :session_key => '_wdtk_cookie_session',
:secret => MySociety::Config.get("COOKIE_STORE_SESSION_SECRET", 'this default is insecure as code is open source, please override for live sites in config/general; this will do for local development')
}
config.action_controller.session_store = :cookie_store
@@ -70,7 +71,7 @@ Rails::Initializer.run do |config|
# Use SQL instead of Active Record's schema dumper when creating the test database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
# like if you have constraints or database-specific column types
- config.active_record.schema_format = :sql
+ # config.active_record.schema_format = :sql
# Activate observers that should always be running
# config.active_record.observers = :cacher, :garbage_collector
@@ -112,6 +113,11 @@ if (MySociety::Config.get("DOMAIN", "") != "")
}
end
+# fallback locale and available locales
+I18n.default_locale = :en
+available_locales = MySociety::Config.get('AVAILABLE_LOCALES', 'en')
+FastGettext.default_available_locales = available_locales.split(/ /)
+
# Load monkey patches and other things from lib/
require 'tmail_extensions.rb'
require 'activesupport_cache_extensions.rb'
@@ -123,5 +129,4 @@ require 'activerecord_errors_extensions.rb'
require 'willpaginate_hack.rb'
require 'sendmail_return_path.rb'
require 'tnef.rb'
-
-
+require 'i18n_fixes.rb'
diff --git a/config/environments/development.rb b/config/environments/development.rb
index d15af3336..d5f2f5772 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -21,3 +21,5 @@ config.action_mailer.delivery_method = :sendmail # so is queued, rather than giv
# unintentionally kept references to objects, especially strings.
# require 'memory_profiler'
# MemoryProfiler.start :string_debug => true, :delay => 10
+
+config.gem "gettext", :version => '>=1.9.3', :lib => false
diff --git a/config/i18n-routes.yml b/config/i18n-routes.yml
new file mode 100644
index 000000000..1f9b3028c
--- /dev/null
+++ b/config/i18n-routes.yml
@@ -0,0 +1,6 @@
+en:
+ # default from routes.rb
+es:
+ search: busquedas
+ help: ayuda
+ about: sobre
diff --git a/config/initializers/fast_gettext.rb b/config/initializers/fast_gettext.rb
index 9ce0955e9..b01b129fa 100644
--- a/config/initializers/fast_gettext.rb
+++ b/config/initializers/fast_gettext.rb
@@ -1,3 +1,3 @@
-FastGettext.add_text_domain 'app', :path => File.join(RAILS_ROOT, 'locale'), :type => :po
-FastGettext.default_available_locales = ['en'] #all you want to allow
-FastGettext.default_text_domain = 'app' \ No newline at end of file
+FastGettext.add_text_domain 'app', :path => 'locale', :type => :po
+FastGettext.default_available_locales = ['en','es'] #all you want to allow
+FastGettext.default_text_domain = 'app'
diff --git a/config/locales b/config/locales
new file mode 120000
index 000000000..748fbfcbe
--- /dev/null
+++ b/config/locales
@@ -0,0 +1 @@
+/home/seb/Code/alaveteli/vendor/rails-locales/rails/locale \ No newline at end of file
diff --git a/config/routes.rb b/config/routes.rb
index 928bacf67..2bf8e87fb 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -17,7 +17,7 @@ ActionController::Routing::Routes.draw do |map|
map.with_options :controller => 'general' do |general|
general.frontpage '/', :action => 'frontpage'
general.blog '/blog', :action => 'blog'
-
+ general.custom_css '/custom.css', :action => 'custom_css'
general.search_redirect '/search', :action => 'search_redirect'
# XXX combined is the search query, and then if sorted a "/newest" at the end.
# Couldn't find a way to do this in routes which also picked up multiple other slashes
@@ -31,7 +31,9 @@ ActionController::Routing::Routes.draw do |map|
end
map.with_options :controller => 'request' do |request|
- request.request_list '/list/:view', :action => 'list', :view => nil
+ request.request_list_recent '/list/recent', :action => 'list', :view => 'recent'
+ request.request_list_successful '/list/successful', :action => 'list', :view => 'successful'
+ request.request_list '/list', :action => 'list'
request.new_request '/new', :action => 'new'
request.new_request_to_body '/new/:url_name', :action => 'new'
@@ -107,6 +109,9 @@ ActionController::Routing::Routes.draw do |map|
map.with_options :controller => 'help' do |help|
help.help_unhappy '/help/unhappy/:url_title', :action => 'unhappy'
+ help.help_about '/help/about', :action => 'about'
+ help.help_contact '/help/contact', :action => 'contact'
+ help.help_requesting '/help/requesting', :action => 'requesting'
help.help_general '/help/:action', :action => :action
end
@@ -120,22 +125,80 @@ ActionController::Routing::Routes.draw do |map|
game.stop '/categorise/stop', :action => 'stop'
end
- # NB: We don't use routes to *construct* admin URLs, as they need to be relative
- # paths to work on the live site proxied over HTTPS to secure.mysociety.org
- map.connect '/admin/', :controller => 'admin_general', :action => 'index'
- map.connect '/admin/timeline', :controller => 'admin_general', :action => 'timeline'
- map.connect '/admin/debug', :controller => 'admin_general', :action => 'debug'
- map.connect '/admin/stats', :controller => 'admin_general', :action => 'stats'
- map.connect '/admin/missing_scheme', :controller => 'admin_public_body', :action => 'missing_scheme'
- map.connect '/admin/unclassified', :controller => 'admin_request', :action => 'list_old_unclassified'
- map.connect '/admin/body/:action/:id', :controller => 'admin_public_body'
- map.connect '/admin/request/:action/:id', :controller => 'admin_request'
- map.connect '/admin/user/:action/:id', :controller => 'admin_user'
- map.connect '/admin/track/:action/:id', :controller => 'admin_track'
- map.connect '/admin/censor/:action/:id', :controller => 'admin_censor_rule'
+ map.with_options :controller => 'admin_public_body' do |body|
+ body.admin_body_missing '/admin/missing_scheme', :action => 'missing_scheme'
+ body.admin_body_index '/admin/body', :action => 'index'
+ body.admin_body_list '/admin/body/list', :action => 'list'
+ body.admin_body_show '/admin/body/show/:id', :action => 'show'
+ body.admin_body_new '/admin/body/new/:id', :action => 'new'
+ body.admin_body_edit '/admin/body/edit/:id', :action => 'edit'
+ body.admin_body_update '/admin/body/update/:id', :action => 'update'
+ body.admin_body_create '/admin/body/create/:id', :action => 'create'
+ body.admin_body_destroy '/admin/body/destroy/:id', :action => 'destroy'
+ body.admin_body_import_csv '/admin/body/import_csv', :action => 'import_csv'
+ end
+
+ map.with_options :controller => 'admin_general' do |admin|
+ admin.admin_general_index '/admin', :action => 'index'
+ admin.admin_timeline '/admin/timeline', :action => 'timeline'
+ admin.admin_debug '/admin/debug', :action => 'debug'
+ admin.admin_stats '/admin/stats', :action => 'stats'
+ end
+
+ map.with_options :controller => 'admin_request' do |admin|
+ admin.admin_request_list_old_unclassified '/admin/unclassified', :action => 'list_old_unclassified'
+ admin.admin_request_index '/admin/request', :action => 'index'
+ admin.admin_request_list '/admin/request/list', :action => 'list'
+ admin.admin_request_show '/admin/request/show/:id', :action => 'show'
+ admin.admin_request_resend '/admin/request/resend', :action => 'resend'
+ admin.admin_request_edit '/admin/request/edit/:id', :action => 'edit'
+ admin.admin_request_update '/admin/request/update/:id', :action => 'update'
+ admin.admin_request_destroy '/admin/request/destroy/:id', :action => 'fully_destroy'
+ admin.admin_request_edit_outgoing '/admin/request/edit_outgoing/:id', :action => 'edit_outgoing'
+ admin.admin_request_destroy_outgoing '/admin/request/destroy_outgoing/:id', :action => 'destroy_outgoing'
+ admin.admin_request_update_outgoing '/admin/request/update_outgoing/:id', :action => 'update_outgoing'
+ admin.admin_request_edit_comment '/admin/request/edit_comment/:id', :action => 'edit_comment'
+ admin.admin_request_update_comment '/admin/request/update_comment/:id', :action => 'update_comment'
+ admin.admin_request_destroy_incomine '/admin/request/destroy_incoming/:id', :action => 'destroy_incoming'
+ admin.admin_request_redeliver_incoming '/admin/request/redeliver_incoming', :action => 'redeliver_incoming'
+ admin.admin_request_move_request '/admin/request/move_request', :action => 'move_request'
+ admin.admin_request_generate_upload_url '/admin/request/generate_upload_url/:id', :action => 'generate_upload_url'
+ admin.admin_request_show_raw_email '/admin/request/show_raw_email/:id', :action => 'show_raw_email'
+ admin.admin_request_download_raw_email '/admin/request/download_raw_email/:id', :action => 'download_raw_email'
+ admin.admin_request_clarification '/admin/request/clarification', :action => 'mark_event_as_clarification'
+ end
+
+ map.with_options :controller => 'admin_user' do |user|
+ user.admin_user_index '/admin/user', :action => 'index'
+ user.admin_user_list '/admin/user/list', :action => 'list'
+ user.admin_user_list_banned '/admin/user/banned', :action => 'list_banned'
+ user.admin_user_show '/admin/user/show/:id', :action => 'show'
+ user.admin_user_edit '/admin/user/edit/:id', :action => 'edit'
+ user.admin_user_update '/admin/user/update/:id', :action => 'update'
+ user.admin_user_destroy_track '/admin/user/destroy_track', :action => 'destroy_track'
+ user.admin_user_login_as '/admin/user/login_as/:id', :action => 'login_as'
+ user.admin_clear_profile_photo '/admin/user/clear_profile_photo/:id', :action => 'clear_profile_photo'
+ end
+
+ map.with_options :controller => 'admin_track' do |track|
+ track.admin_track_list '/admin/track/list', :action => 'list'
+ end
+
+ map.with_options :controller => 'admin_censor_rule' do |rule|
+ rule.admin_rule_new '/admin/censor/new', :action => 'new'
+ rule.admin_rule_create '/admin/censor/create', :action => 'create'
+ rule.admin_rule_edit '/admin/censor/edit/:id', :action => 'edit'
+ rule.admin_rule_update '/admin/censor/update', :action => 'update'
+ rule.admin_rule_destroy '/admin/censor/destroy', :action => 'destroy'
+ end
# Allow downloading Web Service WSDL as a file with an extension
# instead of a file named 'wsdl'
# map.connect ':controller/service.wsdl', :action => 'wsdl'
end
+# XXX should do something like the following to load routes from separate files
+# Dir.glob("config/routes_*yml").each do |f|
+# ActionController::Routing::Translator.translate_from_file(f)
+# end
+ActionController::Routing::Translator.translate_from_file('config', 'i18n-routes.yml')
diff --git a/db/migrate/096_create_translation_tables.rb b/db/migrate/096_create_translation_tables.rb
new file mode 100644
index 000000000..9d7cc65ad
--- /dev/null
+++ b/db/migrate/096_create_translation_tables.rb
@@ -0,0 +1,27 @@
+class CreateTranslationTables < ActiveRecord::Migration
+ def self.up
+ fields = {:name => :text,
+ :short_name => :text,
+ :request_email => :text,
+ :url_name => :text,
+ :notes => :text,
+ :first_letter => :string,
+ :publication_scheme => :text}
+ PublicBody.create_translation_table!(fields)
+
+ # copy current values across to default locale
+ PublicBody.all.each do |publicbody|
+ publicbody.translated_attributes.each do |a, default|
+ value = publicbody.read_attribute(a)
+ unless value.nil?
+ publicbody.send(:"#{a}=", publicbody.read_attribute(a))
+ end
+ end
+ end
+ end
+
+
+ def self.down
+ PublicBody.drop_translation_table!
+ end
+end
diff --git a/db/migrate/097_add_comment_locale.rb b/db/migrate/097_add_comment_locale.rb
new file mode 100644
index 000000000..92ac7c4a5
--- /dev/null
+++ b/db/migrate/097_add_comment_locale.rb
@@ -0,0 +1,10 @@
+class AddCommentLocale < ActiveRecord::Migration
+ def self.up
+ add_column :comments, :locale, :text, :null => false, :default => ""
+ end
+
+ def self.down
+ remove_column :comments, :locale
+ end
+end
+
diff --git a/lib/google_translate.rb b/lib/google_translate.rb
new file mode 100644
index 000000000..369e1de3b
--- /dev/null
+++ b/lib/google_translate.rb
@@ -0,0 +1,18 @@
+require 'rubygems'
+require 'net/http'
+require 'open-uri'
+require 'cgi'
+require 'json'
+
+def detect_language(request, translate_string)
+ google_api_key = ''
+ user_ip = URI.encode(request.env['REMOTE_ADDR'])
+ translate_string = URI.encode(translate_string)
+ url = "http://ajax.googleapis.com/ajax/services/language/detect?v=1.0&q=#{translate_string}&userip=#{user_ip}"
+ if google_api_key != ''
+ url += "&key=#{google_api_key}"
+ end
+ response = Net::HTTP.get_response(URI.parse(url))
+ result = JSON.parse(response.body)
+ result['responseData']['language']
+end
diff --git a/lib/i18n_fixes.rb b/lib/i18n_fixes.rb
new file mode 100644
index 000000000..fad258a72
--- /dev/null
+++ b/lib/i18n_fixes.rb
@@ -0,0 +1,159 @@
+# Some of the monkeypatches in this file should possibly be submitted
+# as patches, but most are here because they should go away when we
+# upgrade to Rails 3.x
+
+# override behaviour in fast_gettext/translation.rb
+# so that we can interpolate our translation strings nicely
+
+def _(key, options = {})
+ translation = FastGettext._(key) || key
+ gettext_interpolate(translation, options)
+end
+
+INTERPOLATION_RESERVED_KEYS = %w(scope default)
+MATCH = /(\\\\)?\{\{([^\}]+)\}\}/
+
+def gettext_interpolate(string, values)
+ return string unless string.is_a?(String)
+ if values.is_a?(Hash)
+ string.gsub(MATCH) do
+ escaped, pattern, key = $1, $2, $2.to_sym
+
+ if escaped
+ pattern
+ elsif INTERPOLATION_RESERVED_KEYS.include?(pattern)
+ raise ReservedInterpolationKey.new(pattern, string)
+ elsif !values.include?(key)
+ raise MissingInterpolationArgument.new(pattern, string)
+ else
+ values[key].to_s
+ end
+ end
+ else
+ reserved_keys = if defined?(I18n::RESERVED_KEYS) # rails 3+
+ I18n::RESERVED_KEYS
+ else
+ I18n::Backend::Base::RESERVED_KEYS
+ end
+
+ string % values.except(*reserved_keys)
+ end
+end
+
+
+module I18n
+ # used by Globalize plugin.
+ # XXX much of this stuff should (might?) be in newer versions of Rails
+ @@fallbacks = nil
+ class << self
+ # Returns the current fallbacks implementation. Defaults to +I18n::Locale::Fallbacks+.
+ def fallbacks
+ @@fallbacks ||= I18n::Locale::Fallbacks.new
+ end
+ end
+
+ module Locale
+ module Tag
+ class Simple
+ class << self
+ def tag(tag)
+ new(tag)
+ end
+ end
+
+ attr_reader :tag
+
+ def initialize(*tag)
+ @tag = tag.join('-').to_sym
+ end
+
+ def subtags
+ @subtags = tag.to_s.split('-').map { |subtag| subtag.to_s }
+ end
+
+ def to_sym
+ tag
+ end
+
+ def to_s
+ tag.to_s
+ end
+
+ def to_a
+ subtags
+ end
+
+ def parent
+ @parent ||= begin
+ segs = to_a.compact
+ segs.length > 1 ? self.class.tag(*segs[0..(segs.length-2)].join('-')) : nil
+ end
+ end
+
+ def self_and_parents
+ @self_and_parents ||= [self] + parents
+ end
+
+ def parents
+ @parents ||= ([parent] + (parent ? parent.parents : [])).compact
+ end
+
+
+ end
+ end
+ class Fallbacks < Hash
+ def initialize(*mappings)
+ @map = {}
+ map(mappings.pop) if mappings.last.is_a?(Hash)
+ self.defaults = mappings.empty? ? [I18n.default_locale.to_sym] : mappings
+ end
+
+ def defaults=(defaults)
+ @defaults = defaults.map { |default| compute(default, false) }.flatten
+ end
+ attr_reader :defaults
+
+ def [](locale)
+ raise InvalidLocale.new(locale) if locale.nil?
+ locale = locale.to_sym
+ super || store(locale, compute(locale))
+ end
+
+ def map(mappings)
+ mappings.each do |from, to|
+ from, to = from.to_sym, Array(to)
+ to.each do |_to|
+ @map[from] ||= []
+ @map[from] << _to.to_sym
+ end
+ end
+ end
+
+ protected
+
+ def compute(tags, include_defaults = true)
+ result = Array(tags).collect do |tag|
+ tags = I18n::Locale::Tag::Simple.tag(tag).self_and_parents.map! { |t| t.to_sym }
+ tags.each { |_tag| tags += compute(@map[_tag]) if @map[_tag] }
+ tags
+ end.flatten
+ result.push(*defaults) if include_defaults
+ result.uniq.compact
+ end
+ end
+ autoload :Fallbacks, 'i18n/locale/fallbacks'
+ end
+end
+
+
+# this monkeypatch corrects inconsistency with gettext_i18n_rails
+# where the latter deals with strings but rails i18n deals with
+# symbols for locales
+module GettextI18nRails
+ class Backend
+ def available_locales
+ FastGettext.available_locales.map{|l| l.to_sym} || []
+ end
+ end
+end
+
diff --git a/lib/tasks/gettext.rake b/lib/tasks/gettext.rake
new file mode 100644
index 000000000..017e7c837
--- /dev/null
+++ b/lib/tasks/gettext.rake
@@ -0,0 +1,5 @@
+namespace :gettext do
+ def files_to_translate
+ Dir.glob("{app,lib,config,locale}/**/*.{rb,erb,haml,rhtml}")
+ end
+end \ No newline at end of file
diff --git a/locale/app.pot b/locale/app.pot
index 86952a61d..59c3f4300 100644
--- a/locale/app.pot
+++ b/locale/app.pot
@@ -7,30 +7,273 @@
msgid ""
msgstr ""
"Project-Id-Version: version 0.0.1\n"
-"POT-Creation-Date: 2011-02-24 11:48-0000\n"
-"PO-Revision-Date: 2011-02-24 07:11-0000\n"
+"POT-Creation-Date: 2011-03-11 13:38-0000\n"
+"PO-Revision-Date: 2011-01-13 16:23-0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
-"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+#: app/views/public_body/show.rhtml:81
+msgid "%d Freedom of Information request"
+msgid_plural "%d Freedom of Information requests"
+msgstr[0] ""
+msgstr[1] ""
+
+#: app/views/general/frontpage.rhtml:36
+msgid "%d request"
+msgid_plural "%d requests"
+msgstr[0] ""
+msgstr[1] ""
+
+#: app/views/general/search.rhtml:53
+msgid "<a href=\"%s\">Browse all</a> or <a href=\"%s\">ask us to add one</a>."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:50
+msgid ""
+"<a href=\"%s\">Make a new Freedom of Information request</a> to "
+"{{public_body_name}}"
+msgstr ""
+
+#: app/views/general/search.rhtml:118
+msgid ""
+"<strong><code>commented_by:tony_bowden</code></strong> to search annotations "
+"made by Tony Bowden, typing the name as in the URL."
+msgstr ""
+
+#: app/views/general/search.rhtml:120
+msgid ""
+"<strong><code>filetype:pdf</code></strong> to find all responses with PDF "
+"attachments. Or try these: <code>{{list_of_file_extensions}}</code>"
+msgstr ""
+
+#: app/views/general/search.rhtml:119
+msgid ""
+"<strong><code>request:</code></strong> to restrict to a specific request, "
+"typing the title as in the URL."
+msgstr ""
+
+#: app/views/general/search.rhtml:117
+msgid ""
+"<strong><code>requested_by:julian_todd</code></strong> to search requests "
+"made by Julian Todd, typing the name as in the URL."
+msgstr ""
+
+#: app/views/general/search.rhtml:116
+msgid ""
+"<strong><code>requested_from:home_office</code></strong> to search requests "
+"from the Home Office, typing the name as in the URL."
+msgstr ""
+
+#: app/views/general/search.rhtml:114
+msgid ""
+"<strong><code>status:</code></strong> to select based on the status or "
+"historical status of the request, see the <a href=\"%s\">table of statuses</"
+"a> below."
+msgstr ""
+
+#: app/views/general/search.rhtml:122
+msgid ""
+"<strong><code>tag:charity</code></strong> to find all public bodies or "
+"requests with a given tag. You can include multiple tags, \n"
+" and tag values, e.g. <code>tag:openlylocal AND tag:"
+"financial_transaction:335633</code>. Note that by default any of the tags\n"
+" can be present, you have to put <code>AND</code> explicitly if you only "
+"want results them all present."
+msgstr ""
+
+#: app/views/general/search.rhtml:115
+msgid ""
+"<strong><code>variety:</code></strong> to select type of thing to search "
+"for, see the <a href=\"%s\">table of varieties</a> below."
+msgstr ""
+
+#: app/models/user.rb:54
+msgid "Admin level is not included in list"
+msgstr ""
+
+#: app/views/general/search.rhtml:31 app/views/general/search.rhtml:109
+msgid "Advanced search tips"
+msgstr ""
+
+#: app/views/general/search.rhtml:17
+msgid ""
+"Can't find it? <a href=\"%s\">Browse all</a> or <a href=\"%s\">ask us to add "
+"it</a>."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:17 app/views/public_body/show.rhtml:19
+msgid "Charity registration"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:147
+msgid "Contact {{site_name}}"
+msgstr ""
+
#: app/models/profile_photo.rb:96
msgid ""
"Couldn't understand the image file that you uploaded. PNG, JPEG, GIF and "
"many other common image file formats are supported."
msgstr ""
+#: app/views/general/search.rhtml:50 app/views/general/search.rhtml:62
+msgid "Did you mean: {{correction}}"
+msgstr ""
+
+#: app/views/admin_public_body/_locale_selector.rhtml:2
+msgid "Edit language version:"
+msgstr ""
+
+#: app/views/comment/_comment_form.rhtml:9
+msgid "Email me future updates to this request"
+msgstr ""
+
+#: app/views/general/search.rhtml:111
+msgid ""
+"Enter words that you want to find separated by spaces, e.g. <strong>climbing "
+"lane</strong>"
+msgstr ""
+
+#: app/views/general/search.rhtml:90
+msgid ""
+"FOI requests {{start_count}} to {{end_count}} of {{total_count}} for "
+"{{user_search_query}}"
+msgstr ""
+
#: app/models/profile_photo.rb:101
msgid "Failed to convert image to a PNG"
msgstr ""
#: app/models/profile_photo.rb:105
msgid ""
-"Failed to convert image to the correct size: at %{cols}x%{rows}, need "
-"%{width}x%{height}"
+"Failed to convert image to the correct size: at %{cols}x%{rows}, need %"
+"{width}x%{height}"
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:8
+msgid ""
+"First, type in the <strong>name of the UK public authority</strong> you'd \n"
+" <br>like information from. <strong>By law, they have to respond</"
+"strong>\n"
+" (<a href=\"%s\">why?</a>)."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:61
+msgid ""
+"For an unknown reason, it is not possible to make a request to this "
+"authority."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:56
+msgid ""
+"Freedom of Information law does not apply to this authority, so you cannot "
+"make\n"
+" a request to it."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:99
+msgid "Freedom of Information requests made"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:73
+msgid "Freedom of Information requests made using this site"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:123
+msgid "Hello!"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:120
+msgid "Hello, {{username}}!"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:115
+msgid "Help"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:8
+msgid "Home page of authority"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:17
+msgid "Make and browse Freedom of Information (FOI) requests"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:89
+msgid "Make and explore Freedom of Information requests"
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:4
+msgid "Make or explore Freedom of Information requests"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:108
+msgid "Make request"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:6
+msgid "More about this authority"
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:41
+msgid "More authorities..."
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:55
+msgid "More successful requests..."
+msgstr ""
+
+#: app/views/layouts/default.rhtml:112
+msgid "My requests"
+msgstr ""
+
+#: app/models/public_body.rb:36
+msgid "Name can't be blank"
+msgstr ""
+
+#: app/models/public_body.rb:40
+msgid "Name is already taken"
+msgstr ""
+
+#: app/views/general/search.rhtml:40
+msgid "Newest results first"
+msgstr ""
+
+#: app/views/general/search.rhtml:16
+msgid "Next, select the public authority you'd like to make the request from."
+msgstr ""
+
+#: app/views/general/search.rhtml:48
+msgid "No public authorities found"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:74
+msgid ""
+"Nobody has made any Freedom of Information requests to {{public_body_name}} "
+"using this site yet."
+msgstr ""
+
+#: app/views/general/search.rhtml:7
+msgid "Nothing found for '{{search_terms}}'"
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:25
+msgid ""
+"OR, <strong>search</strong> for information others have requested using "
+"{{site_name}}"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:92
+msgid "Only requests made using {{site_name}} are shown."
+msgstr ""
+
+#: app/views/general/search.rhtml:80
+msgid ""
+"People {{start_count}} to {{end_count}} of {{total_count}} for "
+"{{user_search_query}}"
msgstr ""
#: app/models/profile_photo.rb:91
@@ -149,6 +392,131 @@ msgid ""
"This makes it easier for others to read."
msgstr ""
-msgid "activerecord.errors.full_messages.format"
-msgstr "%{message}"
+#: app/views/general/search.rhtml:70
+msgid ""
+"Public authorities {{start_count}} to {{end_count}} of {{total_count}} for "
+"{{user_search_query}}"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:11
+msgid "Publication scheme"
+msgstr ""
+
+#: app/views/general/search.rhtml:125
+msgid ""
+"Read about <a href=\"%s\">advanced search operators</a>, such as proximity "
+"and wildcards."
+msgstr ""
+
+#: app/views/layouts/default.rhtml:114
+msgid "Read blog"
+msgstr ""
+
+#: app/views/general/search.rhtml:42
+msgid "Recently described results first"
+msgstr ""
+
+#: app/views/general/search.rhtml:9
+msgid "Results page {{page_number}}"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:102 app/views/general/frontpage.rhtml:16
+#: app/views/general/search.rhtml:29
+msgid "Search"
+msgstr ""
+
+#: app/views/general/search.rhtml:4
+msgid "Search Freedom of Information requests, public authorities and users"
+msgstr ""
+
+#: app/models/public_body.rb:39
+msgid "Short name is already taken"
+msgstr ""
+
+#: app/views/general/search.rhtml:38
+msgid "Show most relevant results first"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:124
+msgid "Sign in or sign up"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:121
+msgid "Sign out"
+msgstr ""
+
+#: app/views/general/search.rhtml:128
+msgid "Table of statuses"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:101
+msgid ""
+"The search index is currently offline, so we can't show the Freedom of "
+"Information requests that have been made to this authority."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:59
+msgid "This authority no longer exists, so you cannot make a request to it."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:4
+msgid "Track this authority"
+msgstr ""
+
+#: app/views/general/search.rhtml:121
+msgid ""
+"Type <strong><code>01/01/2008..14/01/2008</code></strong> to only show "
+"things that happened in the first two weeks of January."
+msgstr ""
+
+#: app/models/public_body.rb:37
+msgid "URL name can't be blank"
+msgstr ""
+
+#: app/views/general/search.rhtml:112
+msgid ""
+"Use OR (in capital letters) where you don't mind which word, e.g. "
+"<strong><code>commons OR lords</code></strong>"
+msgstr ""
+
+#: app/views/general/search.rhtml:113
+msgid ""
+"Use quotes when you want to find an exact phrase, e.g. <strong><code>"
+"\"Liverpool City Council\"</code></strong>"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:23
+msgid "View FOI email address"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:110
+msgid "View authorities"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:109
+msgid "View requests"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:40
+msgid ""
+"You can only request information about the environment from this authority."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:31
+msgid "admin"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:29
+msgid "also called {{public_body_short_name}}"
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:18
+msgid "e.g."
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:51
+msgid "{{length_of_time}} ago"
+msgstr ""
+#~ msgid "activerecord.errors.full_messages.format"
+#~ msgstr "%{message}"
diff --git a/locale/en/app.po b/locale/en/app.po
index 1b942c9aa..d15341b1d 100644
--- a/locale/en/app.po
+++ b/locale/en/app.po
@@ -7,30 +7,274 @@
msgid ""
msgstr ""
"Project-Id-Version: version 0.0.1\n"
-"POT-Creation-Date: 2011-02-24 11:48-0000\n"
+"POT-Creation-Date: 2011-03-11 13:38-0000\n"
"PO-Revision-Date: 2011-02-24 07:11-0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
-"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"Language: \n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+#: app/views/public_body/show.rhtml:81
+msgid "%d Freedom of Information request"
+msgid_plural "%d Freedom of Information requests"
+msgstr[0] ""
+msgstr[1] ""
+
+#: app/views/general/frontpage.rhtml:36
+msgid "%d request"
+msgid_plural "%d requests"
+msgstr[0] ""
+msgstr[1] ""
+
+#: app/views/general/search.rhtml:53
+msgid "<a href=\"%s\">Browse all</a> or <a href=\"%s\">ask us to add one</a>."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:50
+msgid ""
+"<a href=\"%s\">Make a new Freedom of Information request</a> to "
+"{{public_body_name}}"
+msgstr ""
+
+#: app/views/general/search.rhtml:118
+msgid ""
+"<strong><code>commented_by:tony_bowden</code></strong> to search annotations "
+"made by Tony Bowden, typing the name as in the URL."
+msgstr ""
+
+#: app/views/general/search.rhtml:120
+msgid ""
+"<strong><code>filetype:pdf</code></strong> to find all responses with PDF "
+"attachments. Or try these: <code>{{list_of_file_extensions}}</code>"
+msgstr ""
+
+#: app/views/general/search.rhtml:119
+msgid ""
+"<strong><code>request:</code></strong> to restrict to a specific request, "
+"typing the title as in the URL."
+msgstr ""
+
+#: app/views/general/search.rhtml:117
+msgid ""
+"<strong><code>requested_by:julian_todd</code></strong> to search requests "
+"made by Julian Todd, typing the name as in the URL."
+msgstr ""
+
+#: app/views/general/search.rhtml:116
+msgid ""
+"<strong><code>requested_from:home_office</code></strong> to search requests "
+"from the Home Office, typing the name as in the URL."
+msgstr ""
+
+#: app/views/general/search.rhtml:114
+msgid ""
+"<strong><code>status:</code></strong> to select based on the status or "
+"historical status of the request, see the <a href=\"%s\">table of statuses</"
+"a> below."
+msgstr ""
+
+#: app/views/general/search.rhtml:122
+msgid ""
+"<strong><code>tag:charity</code></strong> to find all public bodies or "
+"requests with a given tag. You can include multiple tags, \n"
+" and tag values, e.g. <code>tag:openlylocal AND tag:"
+"financial_transaction:335633</code>. Note that by default any of the tags\n"
+" can be present, you have to put <code>AND</code> explicitly if you only "
+"want results them all present."
+msgstr ""
+
+#: app/views/general/search.rhtml:115
+msgid ""
+"<strong><code>variety:</code></strong> to select type of thing to search "
+"for, see the <a href=\"%s\">table of varieties</a> below."
+msgstr ""
+
+#: app/models/user.rb:54
+msgid "Admin level is not included in list"
+msgstr ""
+
+#: app/views/general/search.rhtml:31 app/views/general/search.rhtml:109
+msgid "Advanced search tips"
+msgstr ""
+
+#: app/views/general/search.rhtml:17
+msgid ""
+"Can't find it? <a href=\"%s\">Browse all</a> or <a href=\"%s\">ask us to add "
+"it</a>."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:17 app/views/public_body/show.rhtml:19
+msgid "Charity registration"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:147
+msgid "Contact {{site_name}}"
+msgstr ""
+
#: app/models/profile_photo.rb:96
msgid ""
"Couldn't understand the image file that you uploaded. PNG, JPEG, GIF and "
"many other common image file formats are supported."
msgstr ""
+#: app/views/general/search.rhtml:50 app/views/general/search.rhtml:62
+msgid "Did you mean: {{correction}}"
+msgstr ""
+
+#: app/views/admin_public_body/_locale_selector.rhtml:2
+msgid "Edit language version:"
+msgstr ""
+
+#: app/views/comment/_comment_form.rhtml:9
+msgid "Email me future updates to this request"
+msgstr ""
+
+#: app/views/general/search.rhtml:111
+msgid ""
+"Enter words that you want to find separated by spaces, e.g. <strong>climbing "
+"lane</strong>"
+msgstr ""
+
+#: app/views/general/search.rhtml:90
+msgid ""
+"FOI requests {{start_count}} to {{end_count}} of {{total_count}} for "
+"{{user_search_query}}"
+msgstr ""
+
#: app/models/profile_photo.rb:101
msgid "Failed to convert image to a PNG"
msgstr ""
#: app/models/profile_photo.rb:105
msgid ""
-"Failed to convert image to the correct size: at %{cols}x%{rows}, need "
-"%{width}x%{height}"
+"Failed to convert image to the correct size: at %{cols}x%{rows}, need %"
+"{width}x%{height}"
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:8
+msgid ""
+"First, type in the <strong>name of the UK public authority</strong> you'd \n"
+" <br>like information from. <strong>By law, they have to respond</"
+"strong>\n"
+" (<a href=\"%s\">why?</a>)."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:61
+msgid ""
+"For an unknown reason, it is not possible to make a request to this "
+"authority."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:56
+msgid ""
+"Freedom of Information law does not apply to this authority, so you cannot "
+"make\n"
+" a request to it."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:99
+msgid "Freedom of Information requests made"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:73
+msgid "Freedom of Information requests made using this site"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:123
+msgid "Hello!"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:120
+msgid "Hello, {{username}}!"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:115
+msgid "Help"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:8
+msgid "Home page of authority"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:17
+msgid "Make and browse Freedom of Information (FOI) requests"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:89
+msgid "Make and explore Freedom of Information requests"
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:4
+msgid "Make or explore Freedom of Information requests"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:108
+msgid "Make request"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:6
+msgid "More about this authority"
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:41
+msgid "More authorities..."
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:55
+msgid "More successful requests..."
+msgstr ""
+
+#: app/views/layouts/default.rhtml:112
+msgid "My requests"
+msgstr ""
+
+#: app/models/public_body.rb:36
+msgid "Name can't be blank"
+msgstr ""
+
+#: app/models/public_body.rb:40
+msgid "Name is already taken"
+msgstr ""
+
+#: app/views/general/search.rhtml:40
+msgid "Newest results first"
+msgstr ""
+
+#: app/views/general/search.rhtml:16
+msgid "Next, select the public authority you'd like to make the request from."
+msgstr ""
+
+#: app/views/general/search.rhtml:48
+msgid "No public authorities found"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:74
+msgid ""
+"Nobody has made any Freedom of Information requests to {{public_body_name}} "
+"using this site yet."
+msgstr ""
+
+#: app/views/general/search.rhtml:7
+msgid "Nothing found for '{{search_terms}}'"
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:25
+msgid ""
+"OR, <strong>search</strong> for information others have requested using "
+"{{site_name}}"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:92
+msgid "Only requests made using {{site_name}} are shown."
+msgstr ""
+
+#: app/views/general/search.rhtml:80
+msgid ""
+"People {{start_count}} to {{end_count}} of {{total_count}} for "
+"{{user_search_query}}"
msgstr ""
#: app/models/profile_photo.rb:91
@@ -149,5 +393,131 @@ msgid ""
"This makes it easier for others to read."
msgstr ""
-msgid "activerecord.errors.full_messages.format"
-msgstr "%{message}"
+#: app/views/general/search.rhtml:70
+msgid ""
+"Public authorities {{start_count}} to {{end_count}} of {{total_count}} for "
+"{{user_search_query}}"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:11
+msgid "Publication scheme"
+msgstr ""
+
+#: app/views/general/search.rhtml:125
+msgid ""
+"Read about <a href=\"%s\">advanced search operators</a>, such as proximity "
+"and wildcards."
+msgstr ""
+
+#: app/views/layouts/default.rhtml:114
+msgid "Read blog"
+msgstr ""
+
+#: app/views/general/search.rhtml:42
+msgid "Recently described results first"
+msgstr ""
+
+#: app/views/general/search.rhtml:9
+msgid "Results page {{page_number}}"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:102 app/views/general/frontpage.rhtml:16
+#: app/views/general/search.rhtml:29
+msgid "Search"
+msgstr ""
+
+#: app/views/general/search.rhtml:4
+msgid "Search Freedom of Information requests, public authorities and users"
+msgstr ""
+
+#: app/models/public_body.rb:39
+msgid "Short name is already taken"
+msgstr ""
+
+#: app/views/general/search.rhtml:38
+msgid "Show most relevant results first"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:124
+msgid "Sign in or sign up"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:121
+msgid "Sign out"
+msgstr ""
+
+#: app/views/general/search.rhtml:128
+msgid "Table of statuses"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:101
+msgid ""
+"The search index is currently offline, so we can't show the Freedom of "
+"Information requests that have been made to this authority."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:59
+msgid "This authority no longer exists, so you cannot make a request to it."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:4
+msgid "Track this authority"
+msgstr ""
+
+#: app/views/general/search.rhtml:121
+msgid ""
+"Type <strong><code>01/01/2008..14/01/2008</code></strong> to only show "
+"things that happened in the first two weeks of January."
+msgstr ""
+
+#: app/models/public_body.rb:37
+msgid "URL name can't be blank"
+msgstr ""
+
+#: app/views/general/search.rhtml:112
+msgid ""
+"Use OR (in capital letters) where you don't mind which word, e.g. "
+"<strong><code>commons OR lords</code></strong>"
+msgstr ""
+
+#: app/views/general/search.rhtml:113
+msgid ""
+"Use quotes when you want to find an exact phrase, e.g. <strong><code>"
+"\"Liverpool City Council\"</code></strong>"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:23
+msgid "View FOI email address"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:110
+msgid "View authorities"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:109
+msgid "View requests"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:40
+msgid ""
+"You can only request information about the environment from this authority."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:31
+msgid "admin"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:29
+msgid "also called {{public_body_short_name}}"
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:18
+msgid "e.g."
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:51
+msgid "{{length_of_time}} ago"
+msgstr ""
+
+#~ msgid "activerecord.errors.full_messages.format"
+#~ msgstr "%{message}"
diff --git a/locale/es/app.po b/locale/es/app.po
new file mode 100644
index 000000000..6166543a0
--- /dev/null
+++ b/locale/es/app.po
@@ -0,0 +1,643 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: version 0.0.1\n"
+"POT-Creation-Date: 2011-03-11 13:38-0000\n"
+"PO-Revision-Date: 2011-03-10 12:27+0000\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=n==0 ? 0 : n==1 ? 1 : 2;\n"
+
+#: app/views/public_body/show.rhtml:81
+#, fuzzy
+msgid "%d Freedom of Information request"
+msgid_plural "%d Freedom of Information requests"
+msgstr[0] "Makando ou exploratre los Libera de Information requesti"
+msgstr[1] "Makando ou exploratre los Libera de Information requesti"
+msgstr[2] "Makando ou exploratre los Libera de Information requesti"
+
+#: app/views/general/frontpage.rhtml:36
+msgid "%d request"
+msgid_plural "%d requests"
+msgstr[0] "nonna requesti"
+msgstr[1] "%d una requestos"
+msgstr[2] "%d multissimo requestos"
+
+#: app/views/general/search.rhtml:53
+msgid "<a href=\"%s\">Browse all</a> or <a href=\"%s\">ask us to add one</a>."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:50
+#, fuzzy
+msgid ""
+"<a href=\"%s\">Make a new Freedom of Information request</a> to "
+"{{public_body_name}}"
+msgstr "Makando ou exploratre los Libera de Information requesti"
+
+#: app/views/general/search.rhtml:118
+msgid ""
+"<strong><code>commented_by:tony_bowden</code></strong> to search annotations "
+"made by Tony Bowden, typing the name as in the URL."
+msgstr ""
+
+#: app/views/general/search.rhtml:120
+msgid ""
+"<strong><code>filetype:pdf</code></strong> to find all responses with PDF "
+"attachments. Or try these: <code>{{list_of_file_extensions}}</code>"
+msgstr ""
+
+#: app/views/general/search.rhtml:119
+msgid ""
+"<strong><code>request:</code></strong> to restrict to a specific request, "
+"typing the title as in the URL."
+msgstr ""
+
+#: app/views/general/search.rhtml:117
+msgid ""
+"<strong><code>requested_by:julian_todd</code></strong> to search requests "
+"made by Julian Todd, typing the name as in the URL."
+msgstr ""
+
+#: app/views/general/search.rhtml:116
+msgid ""
+"<strong><code>requested_from:home_office</code></strong> to search requests "
+"from the Home Office, typing the name as in the URL."
+msgstr ""
+
+#: app/views/general/search.rhtml:114
+msgid ""
+"<strong><code>status:</code></strong> to select based on the status or "
+"historical status of the request, see the <a href=\"%s\">table of statuses</"
+"a> below."
+msgstr ""
+
+#: app/views/general/search.rhtml:122
+msgid ""
+"<strong><code>tag:charity</code></strong> to find all public bodies or "
+"requests with a given tag. You can include multiple tags, \n"
+" and tag values, e.g. <code>tag:openlylocal AND tag:"
+"financial_transaction:335633</code>. Note that by default any of the tags\n"
+" can be present, you have to put <code>AND</code> explicitly if you only "
+"want results them all present."
+msgstr ""
+
+#: app/views/general/search.rhtml:115
+msgid ""
+"<strong><code>variety:</code></strong> to select type of thing to search "
+"for, see the <a href=\"%s\">table of varieties</a> below."
+msgstr ""
+
+#: app/models/user.rb:54
+msgid "Admin level is not included in list"
+msgstr ""
+
+#: app/views/general/search.rhtml:31 app/views/general/search.rhtml:109
+msgid "Advanced search tips"
+msgstr ""
+
+#: app/views/general/search.rhtml:17
+msgid ""
+"Can't find it? <a href=\"%s\">Browse all</a> or <a href=\"%s\">ask us to add "
+"it</a>."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:17 app/views/public_body/show.rhtml:19
+msgid "Charity registration"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:147
+msgid "Contact {{site_name}}"
+msgstr "Engager con la {{site_name}}"
+
+#: app/models/profile_photo.rb:96
+msgid ""
+"Couldn't understand the image file that you uploaded. PNG, JPEG, GIF and "
+"many other common image file formats are supported."
+msgstr ""
+
+#: app/views/general/search.rhtml:50 app/views/general/search.rhtml:62
+msgid "Did you mean: {{correction}}"
+msgstr ""
+
+#: app/views/admin_public_body/_locale_selector.rhtml:2
+msgid "Edit language version:"
+msgstr ""
+
+#: app/views/comment/_comment_form.rhtml:9
+msgid "Email me future updates to this request"
+msgstr ""
+
+#: app/views/general/search.rhtml:111
+msgid ""
+"Enter words that you want to find separated by spaces, e.g. <strong>climbing "
+"lane</strong>"
+msgstr ""
+
+#: app/views/general/search.rhtml:90
+msgid ""
+"FOI requests {{start_count}} to {{end_count}} of {{total_count}} for "
+"{{user_search_query}}"
+msgstr ""
+
+#: app/models/profile_photo.rb:101
+msgid "Failed to convert image to a PNG"
+msgstr ""
+
+#: app/models/profile_photo.rb:105
+msgid ""
+"Failed to convert image to the correct size: at %{cols}x%{rows}, need %"
+"{width}x%{height}"
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:8
+msgid ""
+"First, type in the <strong>name of the UK public authority</strong> you'd \n"
+" <br>like information from. <strong>By law, they have to respond</"
+"strong>\n"
+" (<a href=\"%s\">why?</a>)."
+msgstr ""
+"Premiero, si poco <strong>nomo de Seblando publicus authoritita</strong> "
+"tu \n"
+" <br>amo informatia. <strong>Con legalando, se obligandus "
+"respondre</strong>\n"
+" (<a href=\"%s\">pour acqui?</a>)."
+
+#: app/views/public_body/show.rhtml:61
+msgid ""
+"For an unknown reason, it is not possible to make a request to this "
+"authority."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:56
+msgid ""
+"Freedom of Information law does not apply to this authority, so you cannot "
+"make\n"
+" a request to it."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:99
+#, fuzzy
+msgid "Freedom of Information requests made"
+msgstr "Makando ou exploratre los Libera de Information requesti"
+
+#: app/views/public_body/show.rhtml:73
+#, fuzzy
+msgid "Freedom of Information requests made using this site"
+msgstr "Makando ou exploratre los Libera de Information requesti"
+
+#: app/views/layouts/default.rhtml:123
+msgid "Hello!"
+msgstr "Salutat!"
+
+#: app/views/layouts/default.rhtml:120
+msgid "Hello, {{username}}!"
+msgstr "{{username}} salutato!"
+
+#: app/views/layouts/default.rhtml:115
+msgid "Help"
+msgstr "Ayuder moi"
+
+#: app/views/public_body/show.rhtml:8
+#, fuzzy
+msgid "Home page of authority"
+msgstr "Mas autorita"
+
+#: app/views/layouts/default.rhtml:17
+msgid "Make and browse Freedom of Information (FOI) requests"
+msgstr "Makando ou exploratre los Libera de Information requesti"
+
+#: app/views/layouts/default.rhtml:89
+msgid "Make and explore Freedom of Information requests"
+msgstr "Makando ou exploratre los Libera de Information requesti"
+
+#: app/views/general/frontpage.rhtml:4
+msgid "Make or explore Freedom of Information requests"
+msgstr "Makando ou exploratre los Libera de Information requesti"
+
+#: app/views/layouts/default.rhtml:108
+msgid "Make request"
+msgstr "Creer requesto"
+
+#: app/views/public_body/show.rhtml:6
+#, fuzzy
+msgid "More about this authority"
+msgstr "Mas autorita"
+
+#: app/views/general/frontpage.rhtml:41
+msgid "More authorities..."
+msgstr "Mas autorita"
+
+#: app/views/general/frontpage.rhtml:55
+msgid "More successful requests..."
+msgstr "Mas requesti excellendi"
+
+#: app/views/layouts/default.rhtml:112
+msgid "My requests"
+msgstr "Mes requesti"
+
+#: app/models/public_body.rb:36
+msgid "Name can't be blank"
+msgstr ""
+
+#: app/models/public_body.rb:40
+msgid "Name is already taken"
+msgstr ""
+
+#: app/views/general/search.rhtml:40
+msgid "Newest results first"
+msgstr ""
+
+#: app/views/general/search.rhtml:16
+msgid "Next, select the public authority you'd like to make the request from."
+msgstr ""
+
+#: app/views/general/search.rhtml:48
+#, fuzzy
+msgid "No public authorities found"
+msgstr "Mas autorita"
+
+#: app/views/public_body/show.rhtml:74
+msgid ""
+"Nobody has made any Freedom of Information requests to {{public_body_name}} "
+"using this site yet."
+msgstr ""
+
+#: app/views/general/search.rhtml:7
+msgid "Nothing found for '{{search_terms}}'"
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:25
+msgid ""
+"OR, <strong>search</strong> for information others have requested using "
+"{{site_name}}"
+msgstr ""
+"OU, <strong>busqar</strong> de informationas requestando par los autros avec "
+"{{site_name}}"
+
+#: app/views/public_body/show.rhtml:92
+msgid "Only requests made using {{site_name}} are shown."
+msgstr ""
+
+#: app/views/general/search.rhtml:80
+msgid ""
+"People {{start_count}} to {{end_count}} of {{total_count}} for "
+"{{user_search_query}}"
+msgstr ""
+
+#: app/models/profile_photo.rb:91
+msgid "Please choose a file containing your photo."
+msgstr ""
+
+#: app/models/outgoing_message.rb:162
+msgid "Please choose what sort of reply you are making."
+msgstr ""
+
+#: app/models/info_request.rb:104
+msgid ""
+"Please describe more what the request is about in the subject. There is no "
+"need to say it is an FOI request, we add that on anyway."
+msgstr ""
+
+#: app/models/user.rb:38
+msgid "Please enter a password"
+msgstr ""
+
+#: app/models/contact_validator.rb:30
+msgid "Please enter a subject"
+msgstr ""
+
+#: app/models/info_request.rb:35
+msgid "Please enter a summary of your request"
+msgstr ""
+
+#: app/models/user.rb:106
+msgid "Please enter a valid email address"
+msgstr ""
+
+#: app/models/contact_validator.rb:31
+msgid "Please enter the message you want to send"
+msgstr ""
+
+#: app/models/user.rb:49
+msgid "Please enter the same password twice"
+msgstr ""
+
+#: app/models/comment.rb:59
+msgid "Please enter your annotation"
+msgstr ""
+
+#: app/models/contact_validator.rb:29 app/models/user.rb:34
+msgid "Please enter your email address"
+msgstr ""
+
+#: app/models/outgoing_message.rb:147
+msgid "Please enter your follow up message"
+msgstr ""
+
+#: app/models/outgoing_message.rb:150
+msgid "Please enter your letter requesting information"
+msgstr ""
+
+#: app/models/contact_validator.rb:28 app/models/user.rb:36
+msgid "Please enter your name"
+msgstr ""
+
+#: app/models/user.rb:109
+msgid "Please enter your name, not your email address, in the name field."
+msgstr ""
+
+#: app/models/change_email_validator.rb:29
+msgid "Please enter your new email address"
+msgstr ""
+
+#: app/models/change_email_validator.rb:28
+msgid "Please enter your old email address"
+msgstr ""
+
+#: app/models/change_email_validator.rb:30
+msgid "Please enter your password"
+msgstr ""
+
+#: app/models/outgoing_message.rb:145
+msgid "Please give details explaining why you want a review"
+msgstr ""
+
+#: app/models/about_me_validator.rb:24
+msgid "Please keep it shorter than 500 characters"
+msgstr ""
+
+#: app/models/info_request.rb:101
+msgid ""
+"Please keep the summary short, like in the subject of an email. You can use "
+"a phrase, rather than a full sentence."
+msgstr ""
+
+#: app/models/outgoing_message.rb:156
+msgid ""
+"Please sign at the bottom with your name, or alter the \"%{signoff}\" "
+"signature"
+msgstr ""
+
+#: app/models/info_request.rb:36
+msgid "Please write a summary with some text in it"
+msgstr ""
+
+#: app/models/info_request.rb:98
+msgid ""
+"Please write the summary using a mixture of capital and lower case letters. "
+"This makes it easier for others to read."
+msgstr ""
+
+#: app/models/comment.rb:62
+msgid ""
+"Please write your annotation using a mixture of capital and lower case "
+"letters. This makes it easier for others to read."
+msgstr ""
+
+#: app/models/outgoing_message.rb:159
+msgid ""
+"Please write your message using a mixture of capital and lower case letters. "
+"This makes it easier for others to read."
+msgstr ""
+
+#: app/views/general/search.rhtml:70
+msgid ""
+"Public authorities {{start_count}} to {{end_count}} of {{total_count}} for "
+"{{user_search_query}}"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:11
+#, fuzzy
+msgid "Publication scheme"
+msgstr "Pubiquation escheme"
+
+#: app/views/general/search.rhtml:125
+msgid ""
+"Read about <a href=\"%s\">advanced search operators</a>, such as proximity "
+"and wildcards."
+msgstr ""
+
+#: app/views/layouts/default.rhtml:114
+msgid "Read blog"
+msgstr "Lire bloggus"
+
+#: app/views/general/search.rhtml:42
+msgid "Recently described results first"
+msgstr ""
+
+#: app/views/general/search.rhtml:9
+msgid "Results page {{page_number}}"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:102 app/views/general/frontpage.rhtml:16
+#: app/views/general/search.rhtml:29
+msgid "Search"
+msgstr "Busquar"
+
+#: app/views/general/search.rhtml:4
+#, fuzzy
+msgid "Search Freedom of Information requests, public authorities and users"
+msgstr "Makando ou exploratre los Libera de Information requesti"
+
+#: app/models/public_body.rb:39
+msgid "Short name is already taken"
+msgstr ""
+
+#: app/views/general/search.rhtml:38
+msgid "Show most relevant results first"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:124
+msgid "Sign in or sign up"
+msgstr "Entranter ou ensigner"
+
+#: app/views/layouts/default.rhtml:121
+msgid "Sign out"
+msgstr "Designater"
+
+#: app/views/general/search.rhtml:128
+msgid "Table of statuses"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:101
+msgid ""
+"The search index is currently offline, so we can't show the Freedom of "
+"Information requests that have been made to this authority."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:59
+msgid "This authority no longer exists, so you cannot make a request to it."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:4
+#, fuzzy
+msgid "Track this authority"
+msgstr "Mas autorita"
+
+#: app/views/general/search.rhtml:121
+msgid ""
+"Type <strong><code>01/01/2008..14/01/2008</code></strong> to only show "
+"things that happened in the first two weeks of January."
+msgstr ""
+
+#: app/models/public_body.rb:37
+msgid "URL name can't be blank"
+msgstr ""
+
+#: app/views/general/search.rhtml:112
+msgid ""
+"Use OR (in capital letters) where you don't mind which word, e.g. "
+"<strong><code>commons OR lords</code></strong>"
+msgstr ""
+
+#: app/views/general/search.rhtml:113
+msgid ""
+"Use quotes when you want to find an exact phrase, e.g. <strong><code>"
+"\"Liverpool City Council\"</code></strong>"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:23
+msgid "View FOI email address"
+msgstr ""
+
+#: app/views/layouts/default.rhtml:110
+msgid "View authorities"
+msgstr "Mas autorita"
+
+#: app/views/layouts/default.rhtml:109
+msgid "View requests"
+msgstr "Vider requesti"
+
+#: app/views/public_body/show.rhtml:40
+msgid ""
+"You can only request information about the environment from this authority."
+msgstr ""
+
+#: app/views/public_body/show.rhtml:31
+msgid "admin"
+msgstr ""
+
+#: app/views/public_body/show.rhtml:29
+msgid "also called {{public_body_short_name}}"
+msgstr ""
+
+#: app/views/general/frontpage.rhtml:18
+msgid "e.g."
+msgstr "par exemplo"
+
+#: app/views/general/frontpage.rhtml:51
+msgid "{{length_of_time}} ago"
+msgstr "depuis {{length_of_time}}"
+
+#~ msgid "%d result with exact tag matches"
+#~ msgid_plural "%d results with exact tag matches"
+#~ msgstr[0] "%d resulto con exacto tag matche"
+#~ msgstr[1] "compte de %d resulti con exacto tag matche"
+#~ msgstr[2] "compte de %d resultori con exacto tag matche"
+
+#, fuzzy
+#~ msgid "%d result with substring matches"
+#~ msgid_plural "%d results with substring matches"
+#~ msgstr[0] "%d resulto con exacto tag matche"
+#~ msgstr[1] "compte de %d resulti con exacto tag matche"
+#~ msgstr[2] "compte de %d resultori con exacto tag matche"
+
+#, fuzzy
+#~ msgid "List of all authorities"
+#~ msgstr "Mas autorita"
+
+#, fuzzy
+#~ msgid "Listing public authorities"
+#~ msgstr "Mas autorita"
+
+#, fuzzy
+#~ msgid "Name"
+#~ msgstr "Nom de user"
+
+#~ msgid "OutgoingMessage|Body"
+#~ msgstr "corpus de messago"
+
+#~ msgid "OutgoingMessage|Last sent at"
+#~ msgstr "ultimato envoya"
+
+#~ msgid "OutgoingMessage|Message type"
+#~ msgstr "etypa de messago"
+
+#~ msgid "OutgoingMessage|Status"
+#~ msgstr "estatus"
+
+#~ msgid "OutgoingMessage|What doing"
+#~ msgstr "Faire que"
+
+#~ msgid "PostRedirect|Circumstance"
+#~ msgstr "Circumstancio"
+
+#~ msgid "PostRedirect|Email token"
+#~ msgstr "Token de email"
+
+#~ msgid "ProfilePhoto|Data"
+#~ msgstr "la data"
+
+#~ msgid "ProfilePhoto|Draft"
+#~ msgstr "premerio attemptu"
+
+#, fuzzy
+#~ msgid "PublicBody|"
+#~ msgstr "PublicBody|Nom"
+
+#~ msgid "PublicBody|First letter"
+#~ msgstr "premier sentu"
+
+#~ msgid "PublicBody|Home page"
+#~ msgstr "El maison pago"
+
+#~ msgid "PublicBody|Last edit comment"
+#~ msgstr "ultimate commento de edite"
+
+#~ msgid "PublicBody|Name"
+#~ msgstr "PublicBody|Nom"
+
+#~ msgid "PublicBody|Notes"
+#~ msgstr "Les notios"
+
+#~ msgid "PublicBody|Request email"
+#~ msgstr "requesto emaili"
+
+#~ msgid "PublicBody|Short name"
+#~ msgstr "Nom brevis"
+
+#~ msgid "PublicBody|Url name"
+#~ msgstr "Nom de URL"
+
+#~ msgid "TrackThing|Track medium"
+#~ msgstr "Traq media"
+
+#~ msgid "TrackThing|Track query"
+#~ msgstr "Traq quera"
+
+#~ msgid "TrackThing|Track type"
+#~ msgstr "Etypa de traq"
+
+#~ msgid "User|About me"
+#~ msgstr "Sobre moi"
+
+#~ msgid "User|Email confirmed"
+#~ msgstr "Email econfirmata"
+
+#~ msgid "User|Last daily track email"
+#~ msgstr "La ultimate email de traq quotidiano"
+
+#~ msgid "User|Name"
+#~ msgstr "Nom de user"
+
+#, fuzzy
+#~ msgid "info request"
+#~ msgstr "nonna requesti"
diff --git a/public/images/navimg/alaveteli-logo-header.png b/public/images/navimg/alaveteli-logo-header.png
new file mode 100644
index 000000000..49b529718
--- /dev/null
+++ b/public/images/navimg/alaveteli-logo-header.png
Binary files differ
diff --git a/public/images/navimg/alaveteli-logo.png b/public/images/navimg/alaveteli-logo.png
new file mode 100644
index 000000000..ce9abdd3d
--- /dev/null
+++ b/public/images/navimg/alaveteli-logo.png
Binary files differ
diff --git a/public/stylesheets/ie6-custom.css b/public/stylesheets/ie6-custom.css
new file mode 100644
index 000000000..ae02fe158
--- /dev/null
+++ b/public/stylesheets/ie6-custom.css
@@ -0,0 +1,6 @@
+/* drop your local IE-specific CSS overrides in here */
+
+#banner
+{
+ background-image: url(../images/navimg/alaveteli-100pxd.jpg);
+}
diff --git a/public/stylesheets/main-custom.css b/public/stylesheets/main-custom.css
new file mode 100644
index 000000000..2f68de6b1
--- /dev/null
+++ b/public/stylesheets/main-custom.css
@@ -0,0 +1,18 @@
+/* drop your local CSS overrides in here */
+#banner
+{
+ // background-image: url(../images/navimg/somebanner.jpg);
+}
+
+
+
+#header h1 a
+{
+ background-image: url(../images/navimg/alaveteli-logo.png);
+}
+
+
+#orglogo a
+{
+ background-image: url(../images/navimg/alaveteli-logo-header.png);
+}
diff --git a/public/stylesheets/main.css b/public/stylesheets/main.css
index 70910a535..af52640f7 100644
--- a/public/stylesheets/main.css
+++ b/public/stylesheets/main.css
@@ -36,13 +36,14 @@ body
left: 14px;
height: 55px;
width: 500px;
- z-index: 150;
+ z-index: 200;
text-align: left;
}
#header h1
{
font-size: 0.8em;
line-height: 0em;
+ margin: 0;
}
#header h1 a
@@ -62,6 +63,16 @@ body
margin: 2px 0 0 0;
color: #626262;
}
+
+ #header #user_locale_switcher
+ {
+ font-size: 0.8em;
+ font-style: italic;
+ text-align: left;
+ margin: 2px 0 0 0;
+ color: #626262;
+ position: absolute;
+ }
/*------------------------------------------------ temp stuff */
#staging, #alpha_notice, #beta
{ }
@@ -102,8 +113,8 @@ body
text-align: center;
}
-/*------------------------------------------------ mysoc logo */
- #mysoclogo
+/*------------------------------------------------ org logo */
+ #orglogo
{
position: absolute;
width: 100%;
@@ -115,7 +126,7 @@ body
height: 40px;
z-index: 100;
}
- #mysoclogo a
+ #orglogo a
{
color: #f0f0f0;
display: block;
diff --git a/script/generate_pot.sh b/script/generate_pot.sh
new file mode 100644
index 000000000..69b603748
--- /dev/null
+++ b/script/generate_pot.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+cd `dirname $0`
+
+rake gettext:store_model_attributes
+rake gettext:find
+
+
+rake translate_routes:update_yaml["en es"] \ No newline at end of file
diff --git a/spec/controllers/admin_public_body_controller_spec.rb b/spec/controllers/admin_public_body_controller_spec.rb
index db2e449f8..a48367ae1 100644
--- a/spec/controllers/admin_public_body_controller_spec.rb
+++ b/spec/controllers/admin_public_body_controller_spec.rb
@@ -43,3 +43,57 @@ describe AdminPublicBodyController, "when administering public bodies" do
end
+
+describe AdminPublicBodyController, "when administering public bodies with i18n" do
+ integrate_views
+ fixtures :public_bodies, :public_body_translations
+
+ it "shows the index page" do
+ get :index
+ end
+
+ it "searches for 'humpa'" do
+ get :index, {:query => "humpa", :locale => "es"}
+ assigns[:public_bodies].should == [ public_bodies(:humpadink_public_body) ]
+ end
+
+ it "shows a public body" do
+ get :show, {:id => 2, :locale => "es" }
+ end
+
+ it "creates a new public body" do
+ PublicBody.count.should == 2
+ post :create, { :public_body => { :name => "New Quango", :short_name => "", :tag_string => "blah", :request_email => 'newquango@localhost', :last_edit_comment => 'From test code' } }
+ PublicBody.count.should == 3
+ end
+
+ it "edits a public body" do
+ get :edit, {:id => 3, :locale => 'es'}
+ response.body.should include('Baguette')
+ end
+
+ it "saves edits to a public body" do
+ PublicBody.with_locale(:es) do
+ pb = PublicBody.find(id=3)
+ pb.name.should == "El Department for Humpadinking"
+ end
+
+ post :update, { :id => 3, :public_body => { :name => "Renamed", :short_name => "", :tag_string => "some tags", :request_email => 'edited@localhost', :last_edit_comment => 'From test code' }, :locale => "es" }
+ response.flash[:notice].should include('successful')
+ pb = PublicBody.find(public_bodies(:humpadink_public_body).id)
+ PublicBody.with_locale(:es) do
+ pb.name.should == "Renamed"
+ end
+ PublicBody.with_locale(:en) do
+ pb.name.should == "Department for Humpadinking"
+ end
+ end
+
+ it "destroy a public body" do
+ PublicBody.count.should == 2
+ post :destroy, { :id => 3 }
+ PublicBody.count.should == 1
+ end
+
+
+end
diff --git a/spec/controllers/public_body_controller_spec.rb b/spec/controllers/public_body_controller_spec.rb
index fbab832f6..6b55bc09a 100644
--- a/spec/controllers/public_body_controller_spec.rb
+++ b/spec/controllers/public_body_controller_spec.rb
@@ -4,7 +4,7 @@ require 'json'
describe PublicBodyController, "when showing a body" do
integrate_views
- fixtures :public_bodies, :public_body_versions
+ fixtures :public_bodies, :public_body_versions, :public_body_translations
it "should be successful" do
get :show, :url_name => "dfh"
@@ -21,6 +21,16 @@ describe PublicBodyController, "when showing a body" do
assigns[:public_body].should == public_bodies(:humpadink_public_body)
end
+ it "should assign the body using different locale from that used for url_name" do
+ get :show, {:url_name => "dfh", :locale => 'es'}
+ assigns[:public_body].notes.should == "Baguette"
+ end
+
+ it "should assign the body using same locale as that used in url_name" do
+ get :show, {:url_name => "edfh", :locale => 'es'}
+ assigns[:public_body].notes.should == "Baguette"
+ end
+
it "should redirect to newest name if you use historic name of public body in URL" do
get :show, :url_name => "hdink"
response.should redirect_to(:controller => 'public_body', :action => 'show', :url_name => "dfh")
@@ -51,6 +61,16 @@ describe PublicBodyController, "when listing bodies" do
assigns[:description].should == "all"
end
+ it "should list bodies in alphabetical order with different locale" do
+ get :list, :locale => "es"
+
+ response.should render_template('list')
+
+ assigns[:public_bodies].should == [ public_bodies(:geraldine_public_body), public_bodies(:humpadink_public_body) ]
+ assigns[:tag].should == "all"
+ assigns[:description].should == "all"
+ end
+
it "should list a tagged thing on the appropriate list page, and others on the other page, and all still on the all page" do
public_bodies(:humpadink_public_body).tag_string = "foo local_council"
diff --git a/spec/controllers/track_controller_spec.rb b/spec/controllers/track_controller_spec.rb
index c31491375..a37b1ea01 100644
--- a/spec/controllers/track_controller_spec.rb
+++ b/spec/controllers/track_controller_spec.rb
@@ -37,11 +37,11 @@ describe TrackController, "when sending alerts for a track" do
integrate_views
fixtures :info_requests, :outgoing_messages, :incoming_messages, :raw_emails, :info_request_events, :users, :track_things, :track_things_sent_emails
include LinkToHelper # for main_url
-
+
before do
rebuild_xapian_index
end
-
+
it "should send alerts" do
# set the time the comment event happened at to within the last week
ire = info_request_events(:silly_comment_event)
diff --git a/spec/controllers/user_controller_spec.rb b/spec/controllers/user_controller_spec.rb
index 90f90860a..81da94e67 100644
--- a/spec/controllers/user_controller_spec.rb
+++ b/spec/controllers/user_controller_spec.rb
@@ -125,7 +125,7 @@ describe UserController, "when signing in" do
# check is right confirmation URL
mail_token.should == post_redirect.email_token
- params_from(:get, mail_path).should == { :controller => 'user', :action => 'confirm', :email_token => mail_token }
+ params_from(:get, mail_path).should == { :controller => 'user', :action => 'confirm', :email_token => mail_token, :locale => "en" }
# check confirmation URL works
session[:user_id].should be_nil
@@ -421,7 +421,8 @@ describe UserController, "when changing email address" do
"old_email"=>"bob@localhost",
"new_email"=>"newbob@localhost",
"password"=>"jonespassword"},
- "controller"=>"user"}
+ "controller"=>"user",
+ "locale"=>"en"}
post :signchangeemail, post_redirect.post_params
response.should redirect_to(:controller => 'user', :action => 'show', :url_name => 'bob_smith')
diff --git a/spec/fixtures/public_body_translations.yml b/spec/fixtures/public_body_translations.yml
new file mode 100644
index 000000000..b5e947044
--- /dev/null
+++ b/spec/fixtures/public_body_translations.yml
@@ -0,0 +1,43 @@
+geraldine_es_public_body_translation:
+ name: El A Geraldine Quango
+ first_letter: E
+ request_email: geraldine-requests@localhost
+ id: "1"
+ public_body_id: "2"
+ short_name: eTGQ
+ url_name: etgq
+ locale: es
+ notes: ""
+
+geraldine_en_public_body_translation:
+ name: Geraldine Quango
+ first_letter: G
+ request_email: geraldine-requests@localhost
+ id: "2"
+ public_body_id: "2"
+ short_name: TGQ
+ url_name: tgq
+ locale: en
+ notes: ""
+
+humpadink_es_public_body_translation:
+ name: "El Department for Humpadinking"
+ first_letter: E
+ request_email: humpadink-requests@localhost
+ id: "3"
+ public_body_id: "3"
+ short_name: eDfH
+ url_name: edfh
+ locale: es
+ notes: Baguette
+
+humpadink_en_public_body_translation:
+ name: "Department for Humpadinking"
+ first_letter: D
+ request_email: humpadink-requests@localhost
+ id: "4"
+ public_body_id: "3"
+ short_name: DfH
+ url_name: dfh
+ locale: en
+ notes: An albatross told me!!!
diff --git a/spec/models/outgoing_mailer_spec.rb b/spec/models/outgoing_mailer_spec.rb
index e86f5635c..71a46f8f8 100644
--- a/spec/models/outgoing_mailer_spec.rb
+++ b/spec/models/outgoing_mailer_spec.rb
@@ -24,7 +24,7 @@ describe OutgoingMailer, " when working out follow up addresses" do
# check the basic entry in the fixture is fine
OutgoingMailer.name_and_email_for_followup(ir, im).should == "foiperson@localhost"
- OutgoingMailer.name_for_followup(ir, im).should == "The Geraldine Quango"
+ OutgoingMailer.name_for_followup(ir, im).should == "Geraldine Quango"
OutgoingMailer.email_for_followup(ir, im).should == "foiperson@localhost"
end
diff --git a/spec/models/xapian_spec.rb b/spec/models/xapian_spec.rb
index 36836d95b..00a88be99 100644
--- a/spec/models/xapian_spec.rb
+++ b/spec/models/xapian_spec.rb
@@ -302,7 +302,6 @@ describe PublicBody, " when indexing authorities by tag" do
xapian_object = InfoRequest.full_search([PublicBody], "tag:mice", 'created_at', true, nil, 100, 1)
xapian_object.results.size.should == 1
xapian_object.results[0][:model] == public_bodies(:geraldine_public_body)
-
xapian_object = InfoRequest.full_search([PublicBody], "tag:mice:3", 'created_at', true, nil, 100, 1)
xapian_object.results.size.should == 1
xapian_object.results[0][:model] == public_bodies(:geraldine_public_body)
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index c6e894584..f0f50d61e 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,7 +1,6 @@
# This file is copied to ~/spec when you run 'ruby script/generate rspec'
# from the project root directory.
ENV["RAILS_ENV"] ||= 'test'
-RAILS_ENV = "test"
require File.expand_path(File.join(File.dirname(__FILE__),'..','config','environment'))
require 'spec/autorun'
require 'spec/rails'
@@ -17,8 +16,6 @@ Spec::Runner.configure do |config|
# If you're not using ActiveRecord you should remove these
# lines, delete config/database.yml and disable :active_record
# in your config/boot.rb
- config.use_transactional_fixtures = true
- config.use_instantiated_fixtures = false
config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
# == Fixtures
@@ -118,6 +115,11 @@ if $tempfilecount.nil?
def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
# Call original process function
+ if parameters.nil?
+ parameters = {:locale => "en"}
+ elsif not parameters.has_key?(:locale)
+ parameters[:locale] = "en"
+ end
self.original_process(action, parameters, session, flash, http_method)
# XXX Is there a better way to check this than calling a private method?
@@ -133,4 +135,4 @@ if $tempfilecount.nil?
else
puts "WARNING: HTML validation script " + $html_validation_script + " not found"
end
-end \ No newline at end of file
+end
diff --git a/todo.txt b/todo.txt
index 24b0e6bd7..e78429960 100644
--- a/todo.txt
+++ b/todo.txt
@@ -6,6 +6,14 @@ Next (things that will reduce admin time mainly)
- "Can I help out" a bit invisible
Destroy request - does it remove the tags?
+Richard says he wants the internationalisation to be so it could be one site
+with combined search. Why obey the notion of a country? I'm not sure, but
+it might be prudent to write it so it can run multiple jurisdictions in
+one deploy, if only for administrative reasoins.
+ - path maybe: lib/juris/uk, lib/juris/eu etc.
+ - consider Single Table Inheritance (harder to back out of though)
+ - http://code.alexreisner.com/articles/single-table-inheritance-in-rails.html
+ - use mixins with explicit include otherwise
Add links to these tags where possible:
ch:* - Bodies that appear on the Register of Companies. '*' is replaced by the company number, which is eight characters long and consists of optional upper-case letters followed by digits.
diff --git a/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb b/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb
index 047321562..fa322fe9b 100644
--- a/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb
+++ b/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb
@@ -668,9 +668,34 @@ module ActsAsXapian
self.class.to_s + "-" + self.id.to_s
end
- # Extract value of a field from the model
def xapian_value(field, type = nil)
- value = self[field] || self.send(field.to_sym)
+ if self.respond_to?("translations")
+ if type == :date or type == :boolean
+ value = single_xapian_value(field, type = type)
+ else
+ values = []
+ for locale in self.translations.map{|x| x.locale}
+ self.class.with_locale(locale) do
+ values << single_xapian_value(field, type=type)
+ end
+ end
+ if values[0].kind_of?(String)
+ values = values.reject{|x| x.nil?}
+ value = values.join(" ")
+ else
+ values = values.map{|x| x[0]}
+ value = values.reject{|x| x.nil?}
+ end
+ end
+ else
+ value = single_xapian_value(field, type = type)
+ end
+ return value
+ end
+
+ # Extract value of a field from the model
+ def single_xapian_value(field, type = nil)
+ value = self.send(field.to_sym) || self[field]
if type == :date
if value.kind_of?(Time)
value.utc.strftime("%Y%m%d")
diff --git a/vendor/plugins/alavetelitheme b/vendor/plugins/alavetelitheme
new file mode 160000
+Subproject c52742cb7c587ed7486686e8ddbe2c4fe51e436
diff --git a/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/i18n_hacks.rb b/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/i18n_hacks.rb
index 3a8ee6f65..22e1b9a77 100644
--- a/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/i18n_hacks.rb
+++ b/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/i18n_hacks.rb
@@ -35,4 +35,6 @@ module I18n
self.locale = current_locale if tmp_locale
end
end
-end \ No newline at end of file
+
+end
+
diff --git a/vendor/plugins/globalize2/LICENSE b/vendor/plugins/globalize2/LICENSE
new file mode 100644
index 000000000..94a6b8160
--- /dev/null
+++ b/vendor/plugins/globalize2/LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2008, 2009 Joshua Harvey
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. \ No newline at end of file
diff --git a/vendor/plugins/globalize2/README.textile b/vendor/plugins/globalize2/README.textile
new file mode 100644
index 000000000..e47e9bf37
--- /dev/null
+++ b/vendor/plugins/globalize2/README.textile
@@ -0,0 +1,86 @@
+h1. Globalize2
+
+Globalize2 is the successor of Globalize for Rails.
+
+It is compatible with and builds on the new "I18n api in Ruby on Rails":http://guides.rubyonrails.org/i18n.html. and adds model translations to ActiveRecord.
+
+Globalize2 is much more lightweight and compatible than its predecessor was. Model translations in Globalize2 use default ActiveRecord features and do not limit any ActiveRecord functionality any more.
+
+h2. Requirements
+
+ActiveRecord
+I18n
+
+(or Rails > 2.2)
+
+h2. Installation
+
+To install Globalize2 with its default setup just use:
+
+<pre><code>
+script/plugin install git://github.com/joshmh/globalize2.git
+</code></pre>
+
+h2. Model translations
+
+Model translations allow you to translate your models' attribute values. E.g.
+
+<pre><code>
+class Post < ActiveRecord::Base
+ translates :title, :text
+end
+</code></pre>
+
+Allows you to values for the attributes :title and :text per locale:
+
+<pre><code>
+I18n.locale = :en
+post.title # => Globalize2 rocks!
+
+I18n.locale = :he
+post.title # => גלובאלייז2 שולט!
+</code></pre>
+
+In order to make this work, you'll need to add the appropriate translation tables. Globalize2 comes with a handy helper method to help you do this. It's called @create_translation_table!@. Here's an example:
+
+<pre><code>
+class CreatePosts < ActiveRecord::Migration
+ def self.up
+ create_table :posts do |t|
+ t.timestamps
+ end
+ Post.create_translation_table! :title => :string, :text => :text
+ end
+ def self.down
+ drop_table :posts
+ Post.drop_translation_table!
+ end
+end
+</code></pre>
+
+Note that the ActiveRecord model @Post@ must already exist and have a @translates@ directive listing the translated fields.
+
+h2. Migration from Globalize
+
+See this script by Tomasz Stachewicz: http://gist.github.com/120867
+
+h2. Changes since Globalize2 v0.1.0
+
+* The association globalize_translations has been renamed to translations.
+
+h2. Alternative Solutions
+
+* "Veger's fork":http://github.com/veger/globalize2 - uses default AR schema for the default locale, delegates to the translations table for other locales only
+* "TranslatableColumns":http://github.com/iain/translatable_columns - have multiple languages of the same attribute in a model (Iain Hecker)
+* "localized_record":http://github.com/glennpow/localized_record - allows records to have localized attributes without any modifications to the database (Glenn Powell)
+* "model_translations":http://github.com/janne/model_translations - Minimal implementation of Globalize2 style model translations (Jan Andersson)
+
+h2. Related solutions
+
+* "globalize2_versioning":http://github.com/joshmh/globalize2_versioning - acts_as_versioned style versioning for Globalize2 (Joshua Harvey)
+* "i18n_multi_locales_validations":http://github.com/ZenCocoon/i18n_multi_locales_validations - multi-locales attributes validations to validates attributes from Globalize2 translations models (Sébastien Grosjean)
+* "Globalize2 Demo App":http://github.com/svenfuchs/globalize2-demo - demo application for Globalize2 (Sven Fuchs)</li>
+* "migrate_from_globalize1":http://gist.github.com/120867 - migrate model translations from Globalize1 to Globalize2 (Tomasz Stachewicz)</li>
+* "easy_globalize2_accessors":http://github.com/astropanic/easy_globalize2_accessors - easily access (read and write) globalize2-translated fields (astropanic, Tomasz Stachewicz)</li>
+* "globalize2-easy-translate":http://github.com/bsamman/globalize2-easy-translate - adds methods to easily access or set translated attributes to your model (bsamman)</li>
+* "batch_translations":http://github.com/alvarezrilla/batch_translations - allow saving multiple Globalize2 translations in the same request (Jose Alvarez Rilla)</li>
diff --git a/vendor/plugins/globalize2/Rakefile b/vendor/plugins/globalize2/Rakefile
new file mode 100644
index 000000000..bc35dada4
--- /dev/null
+++ b/vendor/plugins/globalize2/Rakefile
@@ -0,0 +1,39 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the globalize2 plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+desc 'Generate documentation for the globalize2 plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'Globalize2'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
+
+begin
+ require 'jeweler'
+ Jeweler::Tasks.new do |s|
+ s.name = "globalize2"
+ s.summary = "Rails I18n: de-facto standard library for ActiveRecord data translation"
+ s.description = "Rails I18n: de-facto standard library for ActiveRecord data translation"
+ s.email = "joshmh@gmail.com"
+ s.homepage = "http://github.com/joshmh/globalize2"
+ # s.rubyforge_project = ''
+ s.authors = ["Sven Fuchs, Joshua Harvey, Clemens Kofler, John-Paul Bader"]
+ # s.add_development_dependency ''
+ end
+ Jeweler::GemcutterTasks.new
+rescue LoadError
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
+end
diff --git a/vendor/plugins/globalize2/VERSION b/vendor/plugins/globalize2/VERSION
new file mode 100644
index 000000000..0c62199f1
--- /dev/null
+++ b/vendor/plugins/globalize2/VERSION
@@ -0,0 +1 @@
+0.2.1
diff --git a/vendor/plugins/globalize2/generators/db_backend.rb b/vendor/plugins/globalize2/generators/db_backend.rb
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/plugins/globalize2/generators/db_backend.rb
diff --git a/vendor/plugins/globalize2/generators/templates/db_backend_migration.rb b/vendor/plugins/globalize2/generators/templates/db_backend_migration.rb
new file mode 100644
index 000000000..0f0261113
--- /dev/null
+++ b/vendor/plugins/globalize2/generators/templates/db_backend_migration.rb
@@ -0,0 +1,25 @@
+class ActsAsTaggableMigration < ActiveRecord::Migration
+ def self.up
+ create_table :globalize_translations do |t|
+ t.string :locale, :null => false
+ t.string :key, :null => false
+ t.string :translation
+ t.timestamps
+ end
+
+# TODO: FINISH DOING MIGRATION -- stopped in the middle
+
+ create_table :globalize_translations_map do |t|
+ t.string :key, :null => false
+ t.integer :translation_id, :null => false
+ end
+
+ add_index :taggings, :tag_id
+ add_index :taggings, [:taggable_id, :taggable_type]
+ end
+
+ def self.down
+ drop_table :globalize_translations
+ drop_table :tags
+ end
+end
diff --git a/vendor/plugins/globalize2/globalize2.gemspec b/vendor/plugins/globalize2/globalize2.gemspec
new file mode 100644
index 000000000..89021115e
--- /dev/null
+++ b/vendor/plugins/globalize2/globalize2.gemspec
@@ -0,0 +1,81 @@
+# Generated by jeweler
+# DO NOT EDIT THIS FILE DIRECTLY
+# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+ s.name = %q{globalize2}
+ s.version = "0.2.0"
+
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+ s.authors = ["Sven Fuchs, Joshua Harvey, Clemens Kofler, John-Paul Bader"]
+ s.date = %q{2010-04-22}
+ s.description = %q{Rails I18n: de-facto standard library for ActiveRecord data translation}
+ s.email = %q{joshmh@gmail.com}
+ s.extra_rdoc_files = [
+ "LICENSE",
+ "README.textile"
+ ]
+ s.files = [
+ ".gitignore",
+ "LICENSE",
+ "README.textile",
+ "Rakefile",
+ "VERSION",
+ "generators/db_backend.rb",
+ "generators/templates/db_backend_migration.rb",
+ "globalize2.gemspec",
+ "init.rb",
+ "lib/globalize.rb",
+ "lib/globalize/active_record.rb",
+ "lib/globalize/active_record/adapter.rb",
+ "lib/globalize/active_record/attributes.rb",
+ "lib/globalize/active_record/migration.rb",
+ "lib/i18n/missing_translations_log_handler.rb",
+ "lib/i18n/missing_translations_raise_handler.rb",
+ "test/active_record/fallbacks_test.rb",
+ "test/active_record/migration_test.rb",
+ "test/active_record/sti_translated_test.rb",
+ "test/active_record/translates_test.rb",
+ "test/active_record/translation_class_test.rb",
+ "test/active_record/validation_tests.rb",
+ "test/active_record_test.rb",
+ "test/all.rb",
+ "test/data/models.rb",
+ "test/data/no_globalize_schema.rb",
+ "test/data/schema.rb",
+ "test/i18n/missing_translations_test.rb",
+ "test/test_helper.rb"
+ ]
+ s.homepage = %q{http://github.com/joshmh/globalize2}
+ s.rdoc_options = ["--charset=UTF-8"]
+ s.require_paths = ["lib"]
+ s.rubygems_version = %q{1.3.6}
+ s.summary = %q{Rails I18n: de-facto standard library for ActiveRecord data translation}
+ s.test_files = [
+ "test/active_record/fallbacks_test.rb",
+ "test/active_record/migration_test.rb",
+ "test/active_record/sti_translated_test.rb",
+ "test/active_record/translates_test.rb",
+ "test/active_record/translation_class_test.rb",
+ "test/active_record/validation_tests.rb",
+ "test/active_record_test.rb",
+ "test/all.rb",
+ "test/data/models.rb",
+ "test/data/no_globalize_schema.rb",
+ "test/data/schema.rb",
+ "test/i18n/missing_translations_test.rb",
+ "test/test_helper.rb"
+ ]
+
+ if s.respond_to? :specification_version then
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+ s.specification_version = 3
+
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
+ else
+ end
+ else
+ end
+end
+
diff --git a/vendor/plugins/globalize2/init.rb b/vendor/plugins/globalize2/init.rb
new file mode 100644
index 000000000..a4089251b
--- /dev/null
+++ b/vendor/plugins/globalize2/init.rb
@@ -0,0 +1 @@
+require 'globalize'
diff --git a/vendor/plugins/globalize2/lib/globalize.rb b/vendor/plugins/globalize2/lib/globalize.rb
new file mode 100644
index 000000000..67c1878ec
--- /dev/null
+++ b/vendor/plugins/globalize2/lib/globalize.rb
@@ -0,0 +1,15 @@
+module Globalize
+ autoload :ActiveRecord, 'globalize/active_record'
+
+ class << self
+ def fallbacks?
+ I18n.respond_to?(:fallbacks)
+ end
+
+ def fallbacks(locale)
+ fallbacks? ? I18n.fallbacks[locale] : [locale.to_sym]
+ end
+ end
+end
+
+ActiveRecord::Base.send(:include, Globalize::ActiveRecord)
diff --git a/vendor/plugins/globalize2/lib/globalize/active_record.rb b/vendor/plugins/globalize2/lib/globalize/active_record.rb
new file mode 100644
index 000000000..2915a5737
--- /dev/null
+++ b/vendor/plugins/globalize2/lib/globalize/active_record.rb
@@ -0,0 +1,229 @@
+module Globalize
+ class MigrationError < StandardError; end
+ class MigrationMissingTranslatedField < MigrationError; end
+ class BadMigrationFieldType < MigrationError; end
+
+ module ActiveRecord
+ autoload :Adapter, 'globalize/active_record/adapter'
+ autoload :Attributes, 'globalize/active_record/attributes'
+ autoload :Migration, 'globalize/active_record/migration'
+
+ def self.included(base)
+ base.extend ActMacro
+ end
+
+ class << self
+ def build_translation_class(target, options)
+ options[:table_name] ||= "#{target.table_name.singularize}_translations"
+
+ klass = target.const_defined?(:Translation) ?
+ target.const_get(:Translation) :
+ target.const_set(:Translation, Class.new(::ActiveRecord::Base))
+
+ klass.class_eval do
+ set_table_name(options[:table_name])
+ belongs_to target.name.underscore.gsub('/', '_')
+ def locale; read_attribute(:locale).to_sym; end
+ def locale=(locale); write_attribute(:locale, locale.to_s); end
+ end
+
+ klass
+ end
+ end
+
+ module ActMacro
+ def locale
+ (defined?(@@locale) && @@locale)
+ end
+
+ def locale=(locale)
+ @@locale = locale
+ end
+
+ def translates(*attr_names)
+ return if translates?
+ options = attr_names.extract_options!
+
+ class_inheritable_accessor :translation_class, :translated_attribute_names
+ class_inheritable_writer :required_attributes
+ self.translation_class = ActiveRecord.build_translation_class(self, options)
+ self.translated_attribute_names = attr_names.map(&:to_sym)
+
+ include InstanceMethods
+ extend ClassMethods, Migration
+
+ after_save :save_translations!
+ has_many :translations, :class_name => translation_class.name,
+ :foreign_key => class_name.foreign_key,
+ :dependent => :delete_all,
+ :extend => HasManyExtensions
+
+ named_scope :with_translations, lambda { |locale|
+ conditions = required_attributes.map do |attribute|
+ "#{quoted_translation_table_name}.#{attribute} IS NOT NULL"
+ end
+ conditions << "#{quoted_translation_table_name}.locale = ?"
+ { :include => :translations, :conditions => [conditions.join(' AND '), locale] }
+ }
+
+ attr_names.each { |attr_name| translated_attr_accessor(attr_name) }
+ end
+
+ def translates?
+ included_modules.include?(InstanceMethods)
+ end
+ end
+
+ module HasManyExtensions
+ def by_locale(locale)
+ first(:conditions => { :locale => locale.to_s })
+ end
+
+ def by_locales(locales)
+ all(:conditions => { :locale => locales.map(&:to_s) })
+ end
+ end
+
+ module ClassMethods
+ delegate :set_translation_table_name, :to => :translation_class
+
+ def with_locale(locale)
+ previous_locale, self.locale = self.locale, locale
+ result = yield
+ self.locale = previous_locale
+ result
+ end
+
+ def translation_table_name
+ translation_class.table_name
+ end
+
+ def quoted_translation_table_name
+ translation_class.quoted_table_name
+ end
+
+ def required_attributes
+ @required_attributes ||= reflect_on_all_validations.select do |validation|
+ validation.macro == :validates_presence_of && translated_attribute_names.include?(validation.name)
+ end.map(&:name)
+ end
+
+ def respond_to?(method, *args, &block)
+ method.to_s =~ /^find_by_(\w+)$/ && translated_attribute_names.include?($1.to_sym) || super
+ end
+
+ def method_missing(method, *args)
+ if method.to_s =~ /^find_by_(\w+)$/ && translated_attribute_names.include?($1.to_sym)
+ find_first_by_translated_attr_and_locales($1, args.first)
+ elsif method.to_s =~ /^find_all_by_(\w+)$/ && translated_attribute_names.include?($1.to_sym)
+ find_all_by_translated_attr_and_locales($1, args.first)
+ else
+ super
+ end
+ end
+
+ protected
+
+ def find_first_by_translated_attr_and_locales(name, value)
+ query = "#{translated_attr_name(name)} = ? AND #{translated_attr_name('locale')} IN (?)"
+ locales = Globalize.fallbacks(locale || I18n.locale).map(&:to_s)
+ find(
+ :first,
+ :joins => :translations,
+ :conditions => [query, value, locales],
+ :readonly => false
+ )
+ end
+
+ def find_all_by_translated_attr_and_locales(name, value)
+ query = "#{translated_attr_name(name)} = ? AND #{translated_attr_name('locale')} IN (?)"
+ locales = Globalize.fallbacks(locale || I18n.locale).map(&:to_s)
+ find(
+ :all,
+ :joins => :translations,
+ :conditions => [query, value, locales],
+ :readonly => false
+ )
+ end
+
+ def translated_attr_accessor(name)
+ define_method "#{name}=", lambda { |value|
+ globalize.write(self.class.locale || I18n.locale, name, value)
+ self[name] = value
+ }
+ define_method name, lambda { |*args|
+ globalize.fetch(args.first || self.class.locale || I18n.locale, name)
+ }
+ alias_method "#{name}_before_type_cast", name
+ end
+
+ def translated_attr_name(name)
+ "#{translation_class.table_name}.#{name}"
+ end
+ end
+
+ module InstanceMethods
+ def globalize
+ @globalize ||= Adapter.new self
+ end
+
+ def attributes
+ self.attribute_names.inject({}) do |attrs, name|
+ attrs[name] = read_attribute(name) ||
+ (globalize.fetch(I18n.locale, name) rescue nil)
+ attrs
+ end
+ end
+
+ def attributes=(attributes, *args)
+ if attributes.respond_to?(:delete) && locale = attributes.delete(:locale)
+ self.class.with_locale(locale) { super }
+ else
+ super
+ end
+ end
+
+ def attribute_names
+ translated_attribute_names.map(&:to_s) + super
+ end
+
+ def available_locales
+ translations.scoped(:select => 'DISTINCT locale').map(&:locale)
+ end
+
+ def translated_locales
+ translations.map(&:locale)
+ end
+
+ def translated_attributes
+ translated_attribute_names.inject({}) do |attributes, name|
+ attributes.merge(name => send(name))
+ end
+ end
+
+ def set_translations(options)
+ options.keys.each do |locale|
+ translation = translations.find_by_locale(locale.to_s) ||
+ translations.build(:locale => locale.to_s)
+ translation.update_attributes!(options[locale])
+ end
+ end
+
+ def reload(options = nil)
+ translated_attribute_names.each { |name| @attributes.delete(name.to_s) }
+ globalize.reset
+ super(options)
+ end
+
+ protected
+
+ def save_translations!
+ globalize.save_translations!
+ end
+ end
+ end
+end
+
+def globalize_write(name, value)
+ globalize.write(self.class.locale || I18n.locale, name, value)
+end
diff --git a/vendor/plugins/globalize2/lib/globalize/active_record/adapter.rb b/vendor/plugins/globalize2/lib/globalize/active_record/adapter.rb
new file mode 100644
index 000000000..12f89ec01
--- /dev/null
+++ b/vendor/plugins/globalize2/lib/globalize/active_record/adapter.rb
@@ -0,0 +1,80 @@
+module Globalize
+ module ActiveRecord
+ class Adapter
+ # The cache caches attributes that already were looked up for read access.
+ # The stash keeps track of new or changed values that need to be saved.
+ attr_reader :record, :cache, :stash
+
+ def initialize(record)
+ @record = record
+ @cache = Attributes.new
+ @stash = Attributes.new
+ end
+
+ def fetch(locale, attr_name)
+ cache.contains?(locale, attr_name) ?
+ cache.read(locale, attr_name) :
+ cache.write(locale, attr_name, fetch_attribute(locale, attr_name))
+ end
+
+ def write(locale, attr_name, value)
+ stash.write(locale, attr_name, value)
+ cache.write(locale, attr_name, value)
+ end
+
+ def save_translations!
+ stash.each do |locale, attrs|
+ translation = record.translations.find_or_initialize_by_locale(locale.to_s)
+ attrs.each { |attr_name, value| translation[attr_name] = value }
+ translation.save!
+ end
+ stash.clear
+ end
+
+ def reset
+ cache.clear
+ # stash.clear
+ end
+
+ protected
+
+ def fetch_translation(locale)
+ locale = locale.to_sym
+ record.translations.loaded? ? record.translations.detect { |t| t.locale == locale } :
+ record.translations.by_locale(locale)
+ end
+
+ def fetch_translations(locale)
+ # only query if not already included with :include => translations
+ record.translations.loaded? ? record.translations :
+ record.translations.by_locales(Globalize.fallbacks(locale))
+ end
+
+ def fetch_attribute(locale, attr_name)
+ translations = fetch_translations(locale)
+ value, requested_locale = nil, locale
+
+ Globalize.fallbacks(locale).each do |fallback|
+ translation = translations.detect { |t| t.locale == fallback }
+ value = translation && translation.send(attr_name)
+ locale = fallback && break if value
+ end
+
+ set_metadata(value, :locale => locale, :requested_locale => requested_locale)
+ value
+ end
+
+ def set_metadata(object, metadata)
+ if object.respond_to?(:translation_metadata)
+ object.translation_metadata.merge!(meta_data)
+ end
+ end
+
+ def translation_metadata_accessor(object)
+ return if obj.respond_to?(:translation_metadata)
+ class << object; attr_accessor :translation_metadata end
+ object.translation_metadata ||= {}
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/globalize2/lib/globalize/active_record/attributes.rb b/vendor/plugins/globalize2/lib/globalize/active_record/attributes.rb
new file mode 100644
index 000000000..7bd923ce2
--- /dev/null
+++ b/vendor/plugins/globalize2/lib/globalize/active_record/attributes.rb
@@ -0,0 +1,25 @@
+# Helper class for storing values per locale. Used by Globalize::Adapter
+# to stash and cache attribute values.
+module Globalize
+ module ActiveRecord
+ class Attributes < Hash
+ def [](locale)
+ locale = locale.to_sym
+ self[locale] = {} unless has_key?(locale)
+ self.fetch(locale)
+ end
+
+ def contains?(locale, attr_name)
+ self[locale].has_key?(attr_name)
+ end
+
+ def read(locale, attr_name)
+ self[locale][attr_name]
+ end
+
+ def write(locale, attr_name, value)
+ self[locale][attr_name] = value
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/globalize2/lib/globalize/active_record/migration.rb b/vendor/plugins/globalize2/lib/globalize/active_record/migration.rb
new file mode 100644
index 000000000..fa63aed8c
--- /dev/null
+++ b/vendor/plugins/globalize2/lib/globalize/active_record/migration.rb
@@ -0,0 +1,44 @@
+module Globalize
+ module ActiveRecord
+ module Migration
+ def create_translation_table!(fields)
+ translated_attribute_names.each do |f|
+ raise MigrationMissingTranslatedField, "Missing translated field #{f}" unless fields[f]
+ end
+
+ fields.each do |name, type|
+ if translated_attribute_names.include?(name) && ![:string, :text].include?(type)
+ raise BadMigrationFieldType, "Bad field type for #{name}, should be :string or :text"
+ end
+ end
+
+ self.connection.create_table(translation_table_name) do |t|
+ t.references table_name.sub(/^#{table_name_prefix}/, "").singularize
+ t.string :locale
+ fields.each do |name, type|
+ t.column name, type
+ end
+ t.timestamps
+ end
+
+ self.connection.add_index(
+ translation_table_name,
+ "#{table_name.sub(/^#{table_name_prefix}/, "").singularize}_id",
+ :name => translation_index_name
+ )
+ end
+
+ def translation_index_name
+ require 'digest/sha1'
+ # FIXME what's the max size of an index name?
+ index_name = "index_#{translation_table_name}_on_#{self.table_name.singularize}_id"
+ index_name.size < 50 ? index_name : "index_#{Digest::SHA1.hexdigest(index_name)}"
+ end
+
+ def drop_translation_table!
+ self.connection.remove_index(translation_table_name, :name => translation_index_name) rescue nil
+ self.connection.drop_table(translation_table_name)
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/globalize2/lib/i18n/missing_translations_log_handler.rb b/vendor/plugins/globalize2/lib/i18n/missing_translations_log_handler.rb
new file mode 100644
index 000000000..24c10890a
--- /dev/null
+++ b/vendor/plugins/globalize2/lib/i18n/missing_translations_log_handler.rb
@@ -0,0 +1,41 @@
+# A simple exception handler that behaves like the default exception handler
+# but additionally logs missing translations to a given log.
+#
+# Useful for identifying missing translations during testing.
+#
+# E.g.
+#
+# require 'globalize/i18n/missing_translations_log_handler'
+# I18n.missing_translations_logger = RAILS_DEFAULT_LOGGER
+# I18n.exception_handler = :missing_translations_log_handler
+#
+# To set up a different log file:
+#
+# logger = Logger.new("#{RAILS_ROOT}/log/missing_translations.log")
+# I18n.missing_translations_logger = logger
+
+module I18n
+ @@missing_translations_logger = nil
+
+ class << self
+ def missing_translations_logger
+ @@missing_translations_logger ||= begin
+ require 'logger' unless defined?(Logger)
+ Logger.new(STDOUT)
+ end
+ end
+
+ def missing_translations_logger=(logger)
+ @@missing_translations_logger = logger
+ end
+
+ def missing_translations_log_handler(exception, locale, key, options)
+ if MissingTranslationData === exception
+ missing_translations_logger.warn(exception.message)
+ return exception.message
+ else
+ raise exception
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/globalize2/lib/i18n/missing_translations_raise_handler.rb b/vendor/plugins/globalize2/lib/i18n/missing_translations_raise_handler.rb
new file mode 100644
index 000000000..18237b151
--- /dev/null
+++ b/vendor/plugins/globalize2/lib/i18n/missing_translations_raise_handler.rb
@@ -0,0 +1,25 @@
+# A simple exception handler that behaves like the default exception handler
+# but also raises on missing translations.
+#
+# Useful for identifying missing translations during testing.
+#
+# E.g.
+#
+# require 'globalize/i18n/missing_translations_raise_handler'
+# I18n.exception_handler = :missing_translations_raise_handler
+module I18n
+ class << self
+ def missing_translations_raise_handler(exception, locale, key, options)
+ raise exception
+ end
+ end
+end
+
+I18n.exception_handler = :missing_translations_raise_handler
+
+ActionView::Helpers::TranslationHelper.module_eval do
+ def translate(key, options = {})
+ I18n.translate(key, options)
+ end
+ alias :t :translate
+end
diff --git a/vendor/plugins/globalize2/test/active_record/fallbacks_test.rb b/vendor/plugins/globalize2/test/active_record/fallbacks_test.rb
new file mode 100644
index 000000000..449ec8b2b
--- /dev/null
+++ b/vendor/plugins/globalize2/test/active_record/fallbacks_test.rb
@@ -0,0 +1,102 @@
+require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
+require File.expand_path(File.dirname(__FILE__) + '/../data/models')
+
+if I18n.respond_to?(:fallbacks)
+ class TranslatedTest < ActiveSupport::TestCase
+ def setup
+ I18n.locale = :'en-US'
+ I18n.fallbacks.clear
+ reset_db!
+ ActiveRecord::Base.locale = nil
+ end
+
+ def teardown
+ I18n.fallbacks.clear
+ end
+
+ test "keeping one field in new locale when other field is changed" do
+ I18n.fallbacks.map 'de-DE' => [ 'en-US' ]
+ post = Post.create :subject => 'foo'
+ I18n.locale = 'de-DE'
+ post.content = 'bar'
+ assert_equal 'foo', post.subject
+ end
+
+ test "modifying non-required field in a new locale" do
+ I18n.fallbacks.map 'de-DE' => [ 'en-US' ]
+ post = Post.create :subject => 'foo'
+ I18n.locale = 'de-DE'
+ post.content = 'bar'
+ assert post.save
+ end
+
+ test "resolves a simple fallback" do
+ I18n.locale = 'de-DE'
+ post = Post.create :subject => 'foo'
+ I18n.locale = 'de'
+ post.subject = 'baz'
+ post.content = 'bar'
+ post.save
+ I18n.locale = 'de-DE'
+ assert_equal 'foo', post.subject
+ assert_equal 'bar', post.content
+ end
+
+ test "resolves a simple fallback without reloading" do
+ I18n.locale = 'de-DE'
+ post = Post.new :subject => 'foo'
+ I18n.locale = 'de'
+ post.subject = 'baz'
+ post.content = 'bar'
+ I18n.locale = 'de-DE'
+ assert_equal 'foo', post.subject
+ assert_equal 'bar', post.content
+ end
+
+ test "resolves a complex fallback without reloading" do
+ I18n.fallbacks.map 'de' => %w(en he)
+ I18n.locale = 'de'
+ post = Post.new
+ I18n.locale = 'en'
+ post.subject = 'foo'
+ I18n.locale = 'he'
+ post.subject = 'baz'
+ post.content = 'bar'
+ I18n.locale = 'de'
+ assert_equal 'foo', post.subject
+ assert_equal 'bar', post.content
+ end
+
+ test 'fallbacks with lots of locale switching' do
+ I18n.fallbacks.map :'de-DE' => [ :'en-US' ]
+ post = Post.create :subject => 'foo'
+
+ I18n.locale = :'de-DE'
+ assert_equal 'foo', post.subject
+
+ I18n.locale = :'en-US'
+ post.update_attribute :subject, 'bar'
+
+ I18n.locale = :'de-DE'
+ assert_equal 'bar', post.subject
+ end
+
+ test 'fallbacks with lots of locale switching' do
+ I18n.fallbacks.map :'de-DE' => [ :'en-US' ]
+ child = Child.create :content => 'foo'
+
+ I18n.locale = :'de-DE'
+ assert_equal 'foo', child.content
+
+ I18n.locale = :'en-US'
+ child.update_attribute :content, 'bar'
+
+ I18n.locale = :'de-DE'
+ assert_equal 'bar', child.content
+ end
+ end
+end
+
+# TODO should validate_presence_of take fallbacks into account? maybe we need
+# an extra validation call, or more options for validate_presence_of.
+
diff --git a/vendor/plugins/globalize2/test/active_record/migration_test.rb b/vendor/plugins/globalize2/test/active_record/migration_test.rb
new file mode 100644
index 000000000..359d811f0
--- /dev/null
+++ b/vendor/plugins/globalize2/test/active_record/migration_test.rb
@@ -0,0 +1,118 @@
+require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
+require File.expand_path(File.dirname(__FILE__) + '/../data/models')
+
+class MigrationTest < ActiveSupport::TestCase
+ def setup
+ reset_db!
+ Post.drop_translation_table!
+ end
+
+ test 'globalize table added' do
+ assert !Post.connection.table_exists?(:post_translations)
+ assert !Post.connection.index_exists?(:post_translations, :post_id)
+
+ Post.create_translation_table!(:subject => :string, :content => :text)
+ assert Post.connection.table_exists?(:post_translations)
+ assert Post.connection.index_exists?(:post_translations, :post_id)
+
+ columns = Post.connection.columns(:post_translations)
+ assert locale = columns.detect { |c| c.name == 'locale' }
+ assert_equal :string, locale.type
+ assert subject = columns.detect { |c| c.name == 'subject' }
+ assert_equal :string, subject.type
+ assert content = columns.detect { |c| c.name == 'content' }
+ assert_equal :text, content.type
+ assert post_id = columns.detect { |c| c.name == 'post_id' }
+ assert_equal :integer, post_id.type
+ assert created_at = columns.detect { |c| c.name == 'created_at' }
+ assert_equal :datetime, created_at.type
+ assert updated_at = columns.detect { |c| c.name == 'updated_at' }
+ assert_equal :datetime, updated_at.type
+ end
+
+ test 'globalize table dropped' do
+ assert !Post.connection.table_exists?( :post_translations )
+ assert !Post.connection.index_exists?( :post_translations, :post_id )
+ Post.create_translation_table! :subject => :string, :content => :text
+ assert Post.connection.table_exists?( :post_translations )
+ assert Post.connection.index_exists?( :post_translations, :post_id )
+ Post.drop_translation_table!
+ assert !Post.connection.table_exists?( :post_translations )
+ assert !Post.connection.index_exists?( :post_translations, :post_id )
+ end
+
+ test 'exception on missing field inputs' do
+ assert_raise Globalize::MigrationMissingTranslatedField do
+ Post.create_translation_table! :content => :text
+ end
+ end
+
+ test 'exception on bad input type' do
+ assert_raise Globalize::BadMigrationFieldType do
+ Post.create_translation_table! :subject => :string, :content => :integer
+ end
+ end
+
+ test "exception on bad input type isn't raised for untranslated fields" do
+ assert_nothing_raised do
+ Post.create_translation_table! :subject => :string, :content => :string, :views_count => :integer
+ end
+ end
+
+ test 'create_translation_table! should not be called on non-translated models' do
+ assert_raise NoMethodError do
+ Blog.create_translation_table! :name => :string
+ end
+ end
+
+ test 'drop_translation_table! should not be called on non-translated models' do
+ assert_raise NoMethodError do
+ Blog.drop_translation_table!
+ end
+ end
+
+ test "translation_index_name returns a readable index name when it's not longer than 50 characters" do
+ assert_equal 'index_post_translations_on_post_id', Post.send(:translation_index_name)
+ end
+
+ test "translation_index_name returns a hashed index name when it's longer than 50 characters" do
+ class UltraLongModelNameWithoutProper < ActiveRecord::Base
+ translates :foo
+ end
+ name = UltraLongModelNameWithoutProper.send(:translation_index_name)
+ assert_match /^index_[a-z0-9]{40}$/, name
+ end
+
+ test 'globalize table added when table has long name' do
+ UltraLongModelNameWithoutProper.create_translation_table!(
+ :subject => :string, :content => :text
+ )
+
+ assert UltraLongModelNameWithoutProper.connection.table_exists?(
+ :ultra_long_model_name_without_proper_translations
+ )
+ assert UltraLongModelNameWithoutProper.connection.index_exists?(
+ :ultra_long_model_name_without_proper_translations,
+ :name => UltraLongModelNameWithoutProper.send(
+ :translation_index_name
+ )
+ )
+ end
+
+ test 'globalize table dropped when table has long name' do
+ UltraLongModelNameWithoutProper.drop_translation_table!
+ UltraLongModelNameWithoutProper.create_translation_table!(
+ :subject => :string, :content => :text
+ )
+ UltraLongModelNameWithoutProper.drop_translation_table!
+
+ assert !UltraLongModelNameWithoutProper.connection.table_exists?(
+ :ultra_long_model_name_without_proper_translations
+ )
+ assert !UltraLongModelNameWithoutProper.connection.index_exists?(
+ :ultra_long_model_name_without_proper_translations,
+ :ultra_long_model_name_without_proper_id
+ )
+ end
+
+end
diff --git a/vendor/plugins/globalize2/test/active_record/sti_translated_test.rb b/vendor/plugins/globalize2/test/active_record/sti_translated_test.rb
new file mode 100644
index 000000000..f529b8d6e
--- /dev/null
+++ b/vendor/plugins/globalize2/test/active_record/sti_translated_test.rb
@@ -0,0 +1,49 @@
+require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
+require File.expand_path(File.dirname(__FILE__) + '/../data/models')
+
+class StiTranslatedTest < ActiveSupport::TestCase
+ def setup
+ I18n.locale = :'en-US'
+ reset_db!
+ end
+
+ test "works with simple dynamic finders" do
+ foo = Child.create :content => 'foo'
+ Child.create :content => 'bar'
+ child = Child.find_by_content('foo')
+ assert_equal foo, child
+ end
+
+ test 'change attribute on globalized model' do
+ child = Child.create :content => 'foo'
+ assert_equal [], child.changed
+ child.content = 'bar'
+ assert_equal [ 'content' ], child.changed
+ child.content = 'baz'
+ assert_member 'content', child.changed
+ end
+
+ test 'change attribute on globalized model after locale switching' do
+ child = Child.create :content => 'foo'
+ assert_equal [], child.changed
+ child.content = 'bar'
+ I18n.locale = :de
+ assert_equal [ 'content' ], child.changed
+ end
+
+ test "saves all locales, even after locale switching" do
+ child = Child.new :content => 'foo'
+ I18n.locale = 'de-DE'
+ child.content = 'bar'
+ I18n.locale = 'he-IL'
+ child.content = 'baz'
+ child.save
+ I18n.locale = 'en-US'
+ child = Child.first
+ assert_equal 'foo', child.content
+ I18n.locale = 'de-DE'
+ assert_equal 'bar', child.content
+ I18n.locale = 'he-IL'
+ assert_equal 'baz', child.content
+ end
+end
diff --git a/vendor/plugins/globalize2/test/active_record/translates_test.rb b/vendor/plugins/globalize2/test/active_record/translates_test.rb
new file mode 100644
index 000000000..1831063fb
--- /dev/null
+++ b/vendor/plugins/globalize2/test/active_record/translates_test.rb
@@ -0,0 +1,96 @@
+require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
+require File.expand_path(File.dirname(__FILE__) + '/../data/models')
+
+class TranslatesTest < ActiveSupport::TestCase
+ def setup
+ I18n.locale = nil
+ ActiveRecord::Base.locale = nil
+ reset_db!
+ end
+
+ test 'defines a :locale accessors on ActiveRecord::Base' do
+ ActiveRecord::Base.locale = :de
+ assert_equal :de, ActiveRecord::Base.locale
+ end
+
+ test 'the :locale reader on ActiveRecord::Base does not default to I18n.locale (anymore)' do
+ I18n.locale = :en
+ assert_nil ActiveRecord::Base.locale
+ end
+
+ test 'ActiveRecord::Base.with_locale temporarily sets the given locale and yields the block' do
+ I18n.locale = :en
+ post = Post.with_locale(:de) do
+ Post.create!(:subject => 'Titel', :content => 'Inhalt')
+ end
+ assert_nil Post.locale
+ assert_equal :en, I18n.locale
+
+ I18n.locale = :de
+ assert_equal 'Titel', post.subject
+ end
+
+ test 'translation_class returns the Translation class' do
+ assert_equal Post::Translation, Post.translation_class
+ end
+
+ test 'defines a has_many association on the model class' do
+ assert_has_many Post, :translations
+ end
+
+ test 'defines a scope for retrieving locales that have complete translations' do
+ post = Post.create!(:subject => 'subject', :content => 'content')
+ assert_equal [:en], post.translated_locales
+ end
+
+ test 'sets the given attributes to translated_attribute_names' do
+ assert_equal [:subject, :content], Post.translated_attribute_names
+ end
+
+ test 'defines accessors for the translated attributes' do
+ post = Post.new
+ assert post.respond_to?(:subject)
+ assert post.respond_to?(:subject=)
+ end
+
+ test 'attribute reader without arguments will use the current locale on ActiveRecord::Base or I18n' do
+ post = Post.with_locale(:de) do
+ Post.create!(:subject => 'Titel', :content => 'Inhalt')
+ end
+ I18n.locale = :de
+ assert_equal 'Titel', post.subject
+
+ I18n.locale = :en
+ ActiveRecord::Base.locale = :de
+ assert_equal 'Titel', post.subject
+ end
+
+ test 'attribute reader when passed a locale will use the given locale' do
+ post = Post.with_locale(:de) do
+ Post.create!(:subject => 'Titel', :content => 'Inhalt')
+ end
+ assert_equal 'Titel', post.subject(:de)
+ end
+
+ test 'attribute reader will use the current locale on ActiveRecord::Base or I18n' do
+ post = Post.with_locale(:en) do
+ Post.create!(:subject => 'title', :content => 'content')
+ end
+ I18n.locale = :de
+ post.subject = 'Titel'
+ assert_equal 'Titel', post.subject
+
+ ActiveRecord::Base.locale = :en
+ post.subject = 'title'
+ assert_equal 'title', post.subject
+ end
+
+ test "find_by_xx records have writable attributes" do
+ Post.create :subject => "change me"
+ p = Post.find_by_subject("change me")
+ p.subject = "changed"
+ assert_nothing_raised(ActiveRecord::ReadOnlyRecord) do
+ p.save
+ end
+ end
+end
diff --git a/vendor/plugins/globalize2/test/active_record/translation_class_test.rb b/vendor/plugins/globalize2/test/active_record/translation_class_test.rb
new file mode 100644
index 000000000..1628416d7
--- /dev/null
+++ b/vendor/plugins/globalize2/test/active_record/translation_class_test.rb
@@ -0,0 +1,30 @@
+require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
+require File.expand_path(File.dirname(__FILE__) + '/../data/models')
+
+class TranlationClassTest < ActiveSupport::TestCase
+ def setup
+ reset_db!
+ end
+
+ test 'defines a Translation class nested in the model class' do
+ assert Post.const_defined?(:Translation)
+ end
+
+ test 'defines a belongs_to association' do
+ assert_belongs_to Post::Translation, :post
+ end
+
+ test 'defines a reader for :locale that always returns a symbol' do
+ post = Post::Translation.new
+ post.write_attribute('locale', 'de')
+ assert_equal :de, post.locale
+ end
+
+ test 'defines a write for :locale that always writes a string' do
+ post = Post::Translation.new
+ post.locale = :de
+ assert_equal 'de', post.read_attribute('locale')
+ end
+end
+
+
diff --git a/vendor/plugins/globalize2/test/active_record/validation_tests.rb b/vendor/plugins/globalize2/test/active_record/validation_tests.rb
new file mode 100644
index 000000000..0148fa384
--- /dev/null
+++ b/vendor/plugins/globalize2/test/active_record/validation_tests.rb
@@ -0,0 +1,75 @@
+require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
+require File.expand_path(File.dirname(__FILE__) + '/../data/models')
+
+class ValidationTest < ActiveSupport::TestCase
+ def setup
+ reset_db!
+ end
+
+ def teardown
+ Validatee.instance_variable_set(:@validate_callbacks, CallbackChain.new)
+ end
+
+ test "validates_presence_of" do
+ Validatee.class_eval { validates_presence_of :string }
+ assert !Validatee.new.valid?
+ assert Validatee.new(:string => 'foo').valid?
+ end
+
+ test "validates_confirmation_of" do
+ Validatee.class_eval { validates_confirmation_of :string }
+ assert !Validatee.new(:string => 'foo', :string_confirmation => 'bar').valid?
+ assert Validatee.new(:string => 'foo', :string_confirmation => 'foo').valid?
+ end
+
+ test "validates_acceptance_of" do
+ Validatee.class_eval { validates_acceptance_of :string, :accept => '1' }
+ assert !Validatee.new(:string => '0').valid?
+ assert Validatee.new(:string => '1').valid?
+ end
+
+ test "validates_length_of (:is)" do
+ Validatee.class_eval { validates_length_of :string, :is => 1 }
+ assert !Validatee.new(:string => 'aa').valid?
+ assert Validatee.new(:string => 'a').valid?
+ end
+
+ test "validates_format_of" do
+ Validatee.class_eval { validates_format_of :string, :with => /^\d+$/ }
+ assert !Validatee.new(:string => 'a').valid?
+ assert Validatee.new(:string => '1').valid?
+ end
+
+ test "validates_inclusion_of" do
+ Validatee.class_eval { validates_inclusion_of :string, :in => %(a) }
+ assert !Validatee.new(:string => 'b').valid?
+ assert Validatee.new(:string => 'a').valid?
+ end
+
+ test "validates_exclusion_of" do
+ Validatee.class_eval { validates_exclusion_of :string, :in => %(b) }
+ assert !Validatee.new(:string => 'b').valid?
+ assert Validatee.new(:string => 'a').valid?
+ end
+
+ test "validates_numericality_of" do
+ Validatee.class_eval { validates_numericality_of :string }
+ assert !Validatee.new(:string => 'a').valid?
+ assert Validatee.new(:string => '1').valid?
+ end
+
+ # This doesn't pass and Rails' validates_uniqueness_of implementation doesn't
+ # seem to be extensible easily. One can work around that by either defining
+ # a custom validation on the Validatee model itself, or by using validates_uniqueness_of
+ # on Validatee::Translation.
+ #
+ # test "validates_uniqueness_of" do
+ # Validatee.class_eval { validates_uniqueness_of :string }
+ # Validatee.create!(:string => 'a')
+ # assert !Validatee.new(:string => 'a').valid?
+ # assert Validatee.new(:string => 'b').valid?
+ # end
+
+ # test "validates_associated" do
+ # end
+end \ No newline at end of file
diff --git a/vendor/plugins/globalize2/test/active_record_test.rb b/vendor/plugins/globalize2/test/active_record_test.rb
new file mode 100644
index 000000000..38e247e17
--- /dev/null
+++ b/vendor/plugins/globalize2/test/active_record_test.rb
@@ -0,0 +1,467 @@
+require File.expand_path(File.dirname(__FILE__) + '/test_helper')
+require File.expand_path(File.dirname(__FILE__) + '/data/models')
+
+# Higher level tests.
+
+class ActiveRecordTest < ActiveSupport::TestCase
+ def setup
+ I18n.locale = :en
+ reset_db!
+ ActiveRecord::Base.locale = nil
+ end
+
+ def assert_translated(locale, record, names, expected)
+ I18n.locale = locale
+ assert_equal Array(expected), Array(names).map { |name| record.send(name) }
+ end
+
+ test "a translated record has translations" do
+ assert_equal [], Post.new.translations
+ end
+
+ test "saves a translated version of the record for each locale" do
+ post = Post.create(:subject => 'title')
+ I18n.locale = :de
+ post.update_attributes(:subject => 'Titel')
+
+ assert_equal 2, post.translations.size
+ assert_equal %w(de en), post.translations.map(&:locale).map(&:to_s).sort
+ assert_equal %w(Titel title), post.translations.map(&:subject).sort
+ end
+
+ test "a translated record has German translations" do
+ I18n.locale = :de
+ post = Post.create(:subject => 'foo')
+ assert_equal 1, post.translations.size
+ assert_equal [:de], post.translations.map { |t| t.locale }
+ end
+
+ test "modifiying translated fields while switching locales" do
+ post = Post.create(:subject => 'title', :content => 'content')
+ assert_equal %w(title content), [post.subject, post.content]
+
+ I18n.locale = :de
+ post.subject, post.content = 'Titel', 'Inhalt'
+
+ assert_translated(:de, post, [:subject, :content], %w(Titel Inhalt))
+ assert_translated(:en, post, [:subject, :content], %w(title content))
+ assert_translated(:de, post, [:subject, :content], %w(Titel Inhalt))
+
+ post.save
+ post.reload
+
+ assert_translated(:en, post, [:subject, :content], %w(title content))
+ assert_translated(:de, post, [:subject, :content], %w(Titel Inhalt))
+ end
+
+ test "attribute writers do return their argument" do
+ value = Post.new.subject = 'foo'
+ assert_equal 'foo', value
+ end
+
+ test "update_attribute succeeds with valid values" do
+ post = Post.create(:subject => 'foo', :content => 'bar')
+ post.update_attribute(:subject, 'baz')
+ assert_equal 'baz', Post.first.subject
+ end
+
+ test "update_attributes fails with invalid values" do
+ post = Post.create(:subject => 'foo', :content => 'bar')
+ assert !post.update_attributes(:subject => '')
+ assert_not_nil post.reload.attributes['subject']
+ assert_equal 'foo', post.subject
+ end
+
+ test "passing the locale to create uses the given locale" do
+ post = Post.create(:subject => 'Titel', :content => 'Inhalt', :locale => :de)
+ assert_equal :en, I18n.locale
+ assert_nil ActiveRecord::Base.locale
+
+ I18n.locale = :de
+ assert_equal 'Titel', post.subject
+ end
+
+ test "passing the locale to attributes= uses the given locale" do
+ post = Post.create(:subject => 'title', :content => 'content')
+ post.update_attributes(:subject => 'Titel', :content => 'Inhalt', :locale => :de)
+ post.reload
+
+ assert_equal :en, I18n.locale
+ assert_nil ActiveRecord::Base.locale
+
+ assert_equal 'title', post.subject
+ I18n.locale = :de
+ assert_equal 'Titel', post.subject
+ end
+
+ test 'reload works' do
+ post = Post.create(:subject => 'foo', :content => 'bar')
+ post.subject = 'baz'
+ post.reload
+ assert_equal 'foo', post.subject
+ end
+
+ test "returns nil if no translations are found (unsaved record)" do
+ post = Post.new(:subject => 'foo')
+ assert_equal 'foo', post.subject
+ assert_nil post.content
+ end
+
+ test "returns nil if no translations are found (saved record)" do
+ post = Post.create(:subject => 'foo')
+ post.reload
+ assert_equal 'foo', post.subject
+ assert_nil post.content
+ end
+
+ test "finds a German post" do
+ post = Post.create(:subject => 'foo (en)', :content => 'bar')
+ I18n.locale = :de
+ post = Post.first
+ post.subject = 'baz (de)'
+ post.save
+ assert_equal 'baz (de)', Post.first.subject
+ I18n.locale = :en
+ assert_equal 'foo (en)', Post.first.subject
+ end
+
+ test "saves an English post and loads correctly" do
+ post = Post.create(:subject => 'foo', :content => 'bar')
+ assert post.save
+ post = Post.first
+ assert_equal 'foo', post.subject
+ assert_equal 'bar', post.content
+ end
+
+ test "returns the value for the correct locale, after locale switching" do
+ post = Post.create(:subject => 'foo')
+ I18n.locale = :de
+ post.subject = 'bar'
+ post.save
+ I18n.locale = :en
+ post = Post.first
+ assert_equal 'foo', post.subject
+ I18n.locale = :de
+ assert_equal 'bar', post.subject
+ end
+
+ test "returns the value for the correct locale, after locale switching, without saving" do
+ post = Post.create :subject => 'foo'
+ I18n.locale = :de
+ post.subject = 'bar'
+ I18n.locale = :en
+ assert_equal 'foo', post.subject
+ I18n.locale = :de
+ assert_equal 'bar', post.subject
+ end
+
+ test "saves all locales, even after locale switching" do
+ post = Post.new :subject => 'foo'
+ I18n.locale = :de
+ post.subject = 'bar'
+ I18n.locale = :he
+ post.subject = 'baz'
+ post.save
+ I18n.locale = :en
+ post = Post.first
+ assert_equal 'foo', post.subject
+ I18n.locale = :de
+ assert_equal 'bar', post.subject
+ I18n.locale = :he
+ assert_equal 'baz', post.subject
+ end
+
+ test "works with associations" do
+ blog = Blog.create
+ post1 = blog.posts.create(:subject => 'foo')
+
+ I18n.locale = :de
+ post2 = blog.posts.create(:subject => 'bar')
+ assert_equal 2, blog.posts.size
+
+ I18n.locale = :en
+ assert_equal 'foo', blog.posts.first.subject
+ assert_nil blog.posts.last.subject
+
+ I18n.locale = :de
+ assert_equal 'bar', blog.posts.last.subject
+ end
+
+ test "works with simple dynamic finders" do
+ foo = Post.create(:subject => 'foo')
+ Post.create(:subject => 'bar')
+ post = Post.find_by_subject('foo')
+ assert_equal foo, post
+ end
+
+ test 'change attribute on globalized model' do
+ post = Post.create(:subject => 'foo', :content => 'bar')
+ assert_equal [], post.changed
+ post.subject = 'baz'
+ assert_equal ['subject'], post.changed
+ post.content = 'quux'
+ assert_member 'subject', post.changed
+ assert_member 'content', post.changed
+ end
+
+ test 'change attribute on globalized model after locale switching' do
+ post = Post.create(:subject => 'foo', :content => 'bar')
+ assert_equal [], post.changed
+ post.subject = 'baz'
+ I18n.locale = :de
+ assert_equal ['subject'], post.changed
+ end
+
+ test 'complex writing and stashing' do
+ post = Post.create(:subject => 'foo', :content => 'bar')
+ post.subject = nil
+ assert_nil post.subject
+ assert !post.valid?
+ post.subject = 'stashed_foo'
+ assert_equal 'stashed_foo', post.subject
+ end
+
+ test 'translated class locale setting' do
+ assert ActiveRecord::Base.respond_to?(:locale)
+ assert_equal :en, I18n.locale
+ assert_nil ActiveRecord::Base.locale
+
+ I18n.locale = :de
+ assert_equal :de, I18n.locale
+ assert_nil ActiveRecord::Base.locale
+
+ ActiveRecord::Base.locale = :es
+ assert_equal :de, I18n.locale
+ assert_equal :es, ActiveRecord::Base.locale
+
+ I18n.locale = :fr
+ assert_equal :fr, I18n.locale
+ assert_equal :es, ActiveRecord::Base.locale
+ end
+
+ test "untranslated class responds to locale" do
+ assert Blog.respond_to?(:locale)
+ end
+
+ test "to ensure locales in different classes are the same" do
+ ActiveRecord::Base.locale = :de
+ assert_equal :de, ActiveRecord::Base.locale
+ assert_equal :de, Parent.locale
+
+ Parent.locale = :es
+ assert_equal :es, ActiveRecord::Base.locale
+ assert_equal :es, Parent.locale
+ end
+
+ test "attribute saving goes by content locale and not global locale" do
+ ActiveRecord::Base.locale = :de
+ assert_equal :en, I18n.locale
+ Post.create :subject => 'foo'
+ assert_equal :de, Post.first.translations.first.locale
+ end
+
+ test "attribute loading goes by content locale and not global locale" do
+ post = Post.create(:subject => 'foo')
+ assert_nil ActiveRecord::Base.locale
+
+ ActiveRecord::Base.locale = :de
+ assert_equal :en, I18n.locale
+ post.update_attribute(:subject, 'foo [de]')
+ assert_equal 'foo [de]', Post.first.subject
+
+ ActiveRecord::Base.locale = :en
+ assert_equal 'foo', Post.first.subject
+ end
+
+ test "access content locale before setting" do
+ Globalize::ActiveRecord::ActMacro.class_eval "remove_class_variable(:@@locale)"
+ assert_nothing_raised { ActiveRecord::Base.locale }
+ end
+
+ test "available_locales" do
+ Post.locale = :de
+ post = Post.create(:subject => 'foo')
+ Post.locale = :es
+ post.update_attribute(:subject, 'bar')
+ Post.locale = :fr
+ post.update_attribute(:subject, 'baz')
+ assert_equal [:de, :es, :fr], post.available_locales
+ assert_equal [:de, :es, :fr], Post.first.available_locales
+ end
+
+ test "saving record correctly after post-save reload" do
+ reloader = Reloader.create(:content => 'foo')
+ assert_equal 'foo', reloader.content
+ end
+
+ test "including translations" do
+ I18n.locale = :de
+ Post.create(:subject => "Foo1", :content => "Bar1")
+ Post.create(:subject => "Foo2", :content => "Bar2")
+
+ class << Post
+ def translations_included
+ self.all(:include => :translations)
+ end
+ end
+
+ default = Post.all.map { |x| [x.subject, x.content] }
+ with_include = Post.translations_included.map { |x| [x.subject, x.content] }
+ assert_equal default, with_include
+ end
+
+ test "setting multiple translations at once with options hash" do
+ Post.locale = :de
+ post = Post.create(:subject => "foo1", :content => "foo1")
+ Post.locale = :en
+ post.update_attributes(:subject => "bar1", :content => "bar1")
+
+ options = { :de => {:subject => "foo2", :content => "foo2"},
+ :en => {:subject => "bar2", :content => "bar2"} }
+ post.set_translations options
+ post.reload
+
+ assert ["bar2", "bar2"], [post.subject, post.content]
+ Post.locale = :de
+ assert ["foo2", "foo2"], [post.subject, post.content]
+ end
+
+ test "setting only one translation with set_translations" do
+ Post.locale = :de
+ post = Post.create(:subject => "foo1", :content => "foo1")
+ Post.locale = :en
+ post.update_attributes(:subject => "bar1", :content => "bar1")
+
+ options = { :en => { :subject => "bar2", :content => "bar2" } }
+ post.set_translations options
+ post.reload
+
+ assert ["bar2", "bar2"], [post.subject, post.content]
+ Post.locale = :de
+ assert ["foo1", "foo1"], [post.subject, post.content]
+ end
+
+ test "setting only selected attributes with set_translations" do
+ Post.locale = :de
+ post = Post.create(:subject => "foo1", :content => "foo1")
+ Post.locale = :en
+ post.update_attributes(:subject => "bar1", :content => "bar1")
+
+ options = { :de => { :content => "foo2" }, :en => { :subject => "bar2" } }
+ post.set_translations options
+ post.reload
+
+ assert ["bar2", "bar1"], [post.subject, post.content]
+ Post.locale = :de
+ assert ["foo1", "foo2"], [post.subject, post.content]
+ end
+
+ test "setting invalid attributes raises ArgumentError" do
+ Post.locale = :de
+ post = Post.create(:subject => "foo1", :content => "foo1")
+ Post.locale = :en
+ post.update_attributes(:subject => "bar1", :content => "bar1")
+
+ options = { :de => {:fake => "foo2"} }
+ exception = assert_raise(ActiveRecord::UnknownAttributeError) do
+ post.set_translations options
+ end
+ assert_equal "unknown attribute: fake", exception.message
+ end
+
+ test "reload accepting find options" do
+ p = Post.create(:subject => "Foo", :content => "Bar")
+ assert p.reload(:readonly => true, :lock => true)
+ assert_raise(ArgumentError) { p.reload(:foo => :bar) }
+ end
+
+ test "dependent destroy of translation" do
+ p = Post.create(:subject => "Foo", :content => "Bar")
+ assert_equal 1, PostTranslation.count
+ p.destroy
+ assert_equal 0, PostTranslation.count
+ end
+
+ test "translating subclass of untranslated comment model" do
+ translated_comment = TranslatedComment.create(:post => @post)
+ assert_nothing_raised { translated_comment.translations }
+ end
+
+ test "modifiying translated comments works as expected" do
+ I18n.locale = :en
+ translated_comment = TranslatedComment.create(:post => @post, :content => 'foo')
+ assert_equal 'foo', translated_comment.content
+
+ I18n.locale = :de
+ translated_comment.content = 'bar'
+ assert translated_comment.save
+ assert_equal 'bar', translated_comment.content
+
+ I18n.locale = :en
+ assert_equal 'foo', translated_comment.content
+
+ assert_equal 2, translated_comment.translations.size
+ end
+
+ test "can create a proxy class for a namespaced model" do
+ assert_nothing_raised do
+ module Foo
+ module Bar
+ class Baz < ActiveRecord::Base
+ translates :bumm
+ end
+ end
+ end
+ end
+ end
+
+ test "attribute translated before type cast" do
+ Post.locale = :en
+ post = Post.create(:subject => 'foo', :content => 'bar')
+ Post.locale = :de
+ post.update_attribute(:subject, "German foo")
+ assert_equal 'German foo', post.subject_before_type_cast
+ Post.locale = :en
+ assert_equal 'foo', post.subject_before_type_cast
+ end
+
+ test "don't override existing translation class" do
+ assert PostTranslation.new.respond_to?(:existing_method)
+ end
+
+ test "has_many and named scopes work with globalize" do
+ blog = Blog.create
+ assert_nothing_raised { blog.posts.foobar }
+ end
+
+ test "required_attribuets don't include non-translated attributes" do
+ validations = [
+ stub(:name => :name, :macro => :validates_presence_of),
+ stub(:name => :email, :macro => :validates_presence_of)
+ ]
+ User.expects(:reflect_on_all_validations => validations)
+ assert_equal [:name], User.required_attributes
+ end
+
+ test "attribute_names returns translated and regular attribute names" do
+ Post.create :subject => "foo", :content => "bar"
+ assert_equal Post.last.attribute_names.sort, %w[blog_id content id subject]
+ end
+
+ test "attributes returns translated and regular attributes" do
+ Post.create :subject => "foo", :content => "bar"
+ assert_equal Post.last.attributes.keys.sort, %w[blog_id content id subject]
+ end
+
+ test "to_xml includes translated fields" do
+ Post.create :subject => "foo", :content => "bar"
+ assert Post.last.to_xml =~ /subject/
+ assert Post.last.to_xml =~ /content/
+ end
+end
+
+# TODO error checking for fields that exist in main table, don't exist in
+# proxy table, aren't strings or text
+#
+# TODO allow finding by translated attributes in conditions?
+# TODO generate advanced dynamic finders?
diff --git a/vendor/plugins/globalize2/test/all.rb b/vendor/plugins/globalize2/test/all.rb
new file mode 100644
index 000000000..ff467a176
--- /dev/null
+++ b/vendor/plugins/globalize2/test/all.rb
@@ -0,0 +1,2 @@
+files = Dir[File.dirname(__FILE__) + '/**/*_test.rb']
+files.each { |file| require file } \ No newline at end of file
diff --git a/vendor/plugins/globalize2/test/data/models.rb b/vendor/plugins/globalize2/test/data/models.rb
new file mode 100644
index 000000000..5408d6e23
--- /dev/null
+++ b/vendor/plugins/globalize2/test/data/models.rb
@@ -0,0 +1,56 @@
+#require 'ruby2ruby'
+#require 'parse_tree'
+#require 'parse_tree_extensions'
+#require 'pp'
+
+class PostTranslation < ActiveRecord::Base
+ def existing_method ; end
+end
+
+class Post < ActiveRecord::Base
+ translates :subject, :content
+ validates_presence_of :subject
+ named_scope :foobar, :conditions => { :title => "foobar" }
+end
+
+class Blog < ActiveRecord::Base
+ has_many :posts, :order => 'id ASC'
+end
+
+class Parent < ActiveRecord::Base
+ translates :content
+end
+
+class Child < Parent
+end
+
+class Comment < ActiveRecord::Base
+ validates_presence_of :content
+ belongs_to :post
+end
+
+class TranslatedComment < Comment
+ translates :content
+end
+
+class UltraLongModelNameWithoutProper < ActiveRecord::Base
+ translates :subject, :content
+ validates_presence_of :subject
+end
+
+class Reloader < Parent
+ after_create :do_reload
+
+ def do_reload
+ reload
+ end
+end
+
+class Validatee < ActiveRecord::Base
+ translates :string
+end
+
+class User < ActiveRecord::Base
+ translates :name
+ validates_presence_of :name, :email
+end
diff --git a/vendor/plugins/globalize2/test/data/no_globalize_schema.rb b/vendor/plugins/globalize2/test/data/no_globalize_schema.rb
new file mode 100644
index 000000000..379455ddb
--- /dev/null
+++ b/vendor/plugins/globalize2/test/data/no_globalize_schema.rb
@@ -0,0 +1,11 @@
+# This schema creates tables without columns for the translated fields
+ActiveRecord::Schema.define do
+ create_table :blogs, :force => true do |t|
+ t.string :name
+ end
+
+ create_table :posts, :force => true do |t|
+ t.references :blog
+ end
+end
+
diff --git a/vendor/plugins/globalize2/test/data/schema.rb b/vendor/plugins/globalize2/test/data/schema.rb
new file mode 100644
index 000000000..910dd0855
--- /dev/null
+++ b/vendor/plugins/globalize2/test/data/schema.rb
@@ -0,0 +1,55 @@
+ActiveRecord::Schema.define do
+ create_table :blogs, :force => true do |t|
+ t.string :description
+ end
+
+ create_table :posts, :force => true do |t|
+ t.references :blog
+ end
+
+ create_table :post_translations, :force => true do |t|
+ t.string :locale
+ t.references :post
+ t.string :subject
+ t.text :content
+ end
+
+ create_table :parents, :force => true do |t|
+ end
+
+ create_table :parent_translations, :force => true do |t|
+ t.string :locale
+ t.references :parent
+ t.text :content
+ t.string :type
+ end
+
+ create_table :comments, :force => true do |t|
+ t.references :post
+ end
+
+ create_table :comment_translations, :force => true do |t|
+ t.string :locale
+ t.references :comment
+ t.string :subject
+ t.text :content
+ end
+
+ create_table :validatees, :force => true do |t|
+ end
+
+ create_table :validatee_translations, :force => true do |t|
+ t.string :locale
+ t.references :validatee
+ t.string :string
+ end
+
+ create_table :users, :force => true do |t|
+ t.string :email
+ end
+
+ create_table :users_translations, :force => true do |t|
+ t.references :user
+ t.string :name
+ end
+end
diff --git a/vendor/plugins/globalize2/test/i18n/missing_translations_test.rb b/vendor/plugins/globalize2/test/i18n/missing_translations_test.rb
new file mode 100644
index 000000000..5d0ecd6fc
--- /dev/null
+++ b/vendor/plugins/globalize2/test/i18n/missing_translations_test.rb
@@ -0,0 +1,36 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'i18n/missing_translations_log_handler'
+
+class MissingTranslationsTest < ActiveSupport::TestCase
+ test "defines I18n.missing_translations_logger accessor" do
+ assert I18n.respond_to?(:missing_translations_logger)
+ end
+
+ test "defines I18n.missing_translations_logger= writer" do
+ assert I18n.respond_to?(:missing_translations_logger=)
+ end
+end
+
+class TestLogger < String
+ def warn(msg) self.concat msg; end
+end
+
+class LogMissingTranslationsTest < ActiveSupport::TestCase
+ def setup
+ @locale, @key, @options = :en, :foo, {}
+ @exception = I18n::MissingTranslationData.new(@locale, @key, @options)
+
+ @logger = TestLogger.new
+ I18n.missing_translations_logger = @logger
+ end
+
+ test "still returns the exception message for MissingTranslationData exceptions" do
+ result = I18n.send(:missing_translations_log_handler, @exception, @locale, @key, @options)
+ assert_equal 'translation missing: en, foo', result
+ end
+
+ test "logs the missing translation to I18n.missing_translations_logger" do
+ I18n.send(:missing_translations_log_handler, @exception, @locale, @key, @options)
+ assert_equal 'translation missing: en, foo', @logger
+ end
+end
diff --git a/vendor/plugins/globalize2/test/test_helper.rb b/vendor/plugins/globalize2/test/test_helper.rb
new file mode 100644
index 000000000..99a5d3950
--- /dev/null
+++ b/vendor/plugins/globalize2/test/test_helper.rb
@@ -0,0 +1,76 @@
+$LOAD_PATH << File.expand_path( File.dirname(__FILE__) + '/../lib' )
+
+require 'rubygems'
+require 'test/unit'
+require 'active_record'
+require 'active_support'
+require 'active_support/test_case'
+require 'mocha'
+require 'globalize'
+# require 'validation_reflection'
+
+config = { :adapter => 'sqlite3', :database => ':memory:' }
+ActiveRecord::Base.establish_connection(config)
+
+class ActiveSupport::TestCase
+ def reset_db!(schema_path = nil)
+ schema_path ||= File.expand_path(File.dirname(__FILE__) + '/data/schema.rb')
+ ActiveRecord::Migration.verbose = false
+ ActiveRecord::Base.silence { load(schema_path) }
+ end
+
+ def assert_member(item, array)
+ assert_block "Item #{item} is not in array #{array}" do
+ array.member?(item)
+ end
+ end
+
+ def assert_belongs_to(model, associated)
+ assert model.reflect_on_all_associations(:belongs_to).detect { |association|
+ association.name.to_s == associated.to_s
+ }
+ end
+
+ def assert_has_many(model, associated)
+ assert model.reflect_on_all_associations(:has_many).detect { |association|
+ association.name.to_s == associated.to_s
+ }
+ end
+end
+
+module ActiveRecord
+ module ConnectionAdapters
+ class AbstractAdapter
+ def index_exists?(table_name, column_name)
+ indexes(table_name).any? { |index| index.name == index_name(table_name, column_name) }
+ end
+ end
+ end
+end
+
+# module ActiveRecord
+# class BaseWithoutTable < Base
+# self.abstract_class = true
+#
+# def create_or_update
+# errors.empty?
+# end
+#
+# class << self
+# def columns()
+# @columns ||= []
+# end
+#
+# def column(name, sql_type = nil, default = nil, null = true)
+# columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
+# reset_column_information
+# end
+#
+# # Do not reset @columns
+# def reset_column_information
+# read_methods.each { |name| undef_method(name) }
+# @column_names = @columns_hash = @content_columns = @dynamic_methods_hash = @read_methods = nil
+# end
+# end
+# end
+# end \ No newline at end of file
diff --git a/vendor/plugins/translate_routes/.gitignore b/vendor/plugins/translate_routes/.gitignore
new file mode 100644
index 000000000..943a463d9
--- /dev/null
+++ b/vendor/plugins/translate_routes/.gitignore
@@ -0,0 +1,4 @@
+.DS_Store
+SampleApp/log/*.log
+SampleApp/tmp/**/*
+SampleApp/db/test.sqlite3 \ No newline at end of file
diff --git a/vendor/plugins/translate_routes/ChangeLog b/vendor/plugins/translate_routes/ChangeLog
new file mode 100755
index 000000000..75d0e76b1
--- /dev/null
+++ b/vendor/plugins/translate_routes/ChangeLog
@@ -0,0 +1,22 @@
+-- 0.98
+ Accepted patch from hoelmer: Updated rake task to use I18n yaml format.
+-- 0.97
+ Accepted patch from Aitor Garay-Romero: root routes with prefix now doesn't set the locale parameter.
+
+-- rails2.2 branch -> master
+
+-- branch rails2.2 v0.9 (Oct 27th 2008)
+ * Developed after Rails2.2rc1 release, with i18n support. Beta, not backward compatible with Rails < 2.2
+
+-- 0.96.1 (Aug 5th 2008)
+ * Fixed by Mathieu Fosse: helpers didn't worked as expected when locale_param_key is undefined
+
+-- 0.96 (Jun 10th 2008)
+ * Added update_yaml task, suggested by Francesc Esplugas
+
+-- 0.95 (Jan 21st 2008)
+ * Still beta version
+ * Added yaml files support for dictionaries
+
+-- 0.9 (Dec 27th 2007)
+ * Beta version
diff --git a/vendor/plugins/translate_routes/MIT-LICENSE b/vendor/plugins/translate_routes/MIT-LICENSE
new file mode 100755
index 000000000..fbce523f9
--- /dev/null
+++ b/vendor/plugins/translate_routes/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2007 Raul Murciano [http://raul.murciano.net], Domestika INTERNET S.L. [http://domestika.org]
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/plugins/translate_routes/README.markdown b/vendor/plugins/translate_routes/README.markdown
new file mode 100755
index 000000000..1c0d0bf25
--- /dev/null
+++ b/vendor/plugins/translate_routes/README.markdown
@@ -0,0 +1,99 @@
+TranslateRoutes
+===============
+
+This Rails plugin provides a simple way to translate your URLs to any number of languages, even on a fully working application.
+
+It works fine with all kind of routing definitions, including RESTful and named routes.
+**Your current code will remain untouched**: your current routing code, helpers and links will be translated transparently - even in your tests.
+(Un)installing it is a very clean and simple process, so why don't you give it a chance? ;)
+
+This version works only with Rails 2.2.x. You can find all available versions in [the wiki](wiki.github.com/raul/translate_routes).
+
+Sample application
+------------------
+There is a [sample application](http://github.com/raul/translate_routes_demo/tree/master) which can be very useful to see how to integrate this plugin on your Rails application. The application itself includes all the required steps: 3 lines, an optional filter and a yaml translations file were used.
+
+
+Quick start
+-----------
+
+Let's start with a tiny example. Of course you need to define your routes first, e.g:
+
+ ActionController::Routing::Routes.draw do |map|
+ map.contact 'contact', :controller => 'contact', :action => 'index'
+ end
+
+1) Download the plugin to your app's `/vendor/plugins` directory.
+
+2) Write your translations on a standard YAML file (e.g: i18n-routes.yml), including the locales and it translations pairs:
+
+ es:
+ contact: contacto
+
+
+3) Append a line to your routes.rb file to activate the translations. If you loaded the translations file with
+your other I18n translations files, the line will be:
+
+ ActionController::Routing::Translator.i18n('es')
+
+and if you want to keep the file separated (e.g: config/i18n-routes.yml), the line to append is:
+
+ ActionController::Routing::Translator.translate_from_file('config','i18n-routes.yml')
+
+You can see it working by executing `rake routes` on the shell:
+
+
+ contact_es_es_path /es-ES/contacto {:locale=>"es", :controller=>"contact", :action=>"index"}
+ contact_en_us_path /contact {:locale=>"'en'", :controller=>"contact", :action=>"index"}
+
+
+As we can see, a new spanish route has been setted up and a `locale` parameter has been added to the routes.
+
+4) Include this filter in your ApplicationController:
+
+ before_filter :set_locale_from_url
+
+Now your application recognizes the different routes and sets the `I18n.locale` value on your controllers,
+but what about the routes generation? As you can see on the previous `rake routes` execution, the
+`contact_es_es_path` and `contact_en_us_path` routing helpers have been generated and are
+available in your controllers and views. Additionally, a `contact_path` helper has been generated, which
+generates the routes according to the current request's locale. This way your link
+
+This means that if you use named routes **you don't need to modify your application links** because the routing helpers are automatically adapted to the current locale.
+
+5) Hey, but what about my tests?
+
+Of course, your functional and integration testing involves some requests.
+The plugin includes some code to add a default locale parameter so they can remain untouched.
+Append it to your `test_helper` and it will be applied.
+
+Documentation
+-------------
+You can find additional information in [the translate_routes' wiki](http://wiki.github.com/raul/translate_routes).
+
+Questions, suggestions, bug reports...
+--------------------------------------
+Feedback, questions and comments will be always welcome at raul@murciano.net
+
+Credits
+-------
+* Main development:
+ * Raul Murciano <http://raul.murciano.net> - code
+ * Domestika INTERNET S.L <http://domestika.org> - incredible support, really nice people to work with!
+
+* Contributors:
+ * Aitor Garay-Romero
+ * hoelmer (sorry mate, I can't find your real name)
+
+Rails routing resources
+-----------------------
+* David Black's 'Rails Routing' ebook rocks! - 'Ruby for Rails' too, BTW.
+* Obie Fernandez's 'The Rails Way' - the definitive RoR reference, great work Obie!
+* As a part of the impressive Rails Guides set there is an [awesome document about rails routing](http://guides.rails.info/routing_outside_in.html) by Mike Gunderloy:
+
+
+License
+-------
+ Copyright (c) 2007 Released under the MIT license (see MIT-LICENSE)
+ Raul Murciano <http://raul.murciano.net>
+ Domestika INTERNET S.L. <http://domestika.org> \ No newline at end of file
diff --git a/vendor/plugins/translate_routes/Rakefile b/vendor/plugins/translate_routes/Rakefile
new file mode 100755
index 000000000..5b0a29cf5
--- /dev/null
+++ b/vendor/plugins/translate_routes/Rakefile
@@ -0,0 +1,22 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the translate_routes plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+desc 'Generate documentation for the translate_routes plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'TranslateRoutes'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
diff --git a/vendor/plugins/translate_routes/config/routes_en-US.yml b/vendor/plugins/translate_routes/config/routes_en-US.yml
new file mode 100755
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/plugins/translate_routes/config/routes_en-US.yml
diff --git a/vendor/plugins/translate_routes/config/routes_es-ES.yml b/vendor/plugins/translate_routes/config/routes_es-ES.yml
new file mode 100755
index 000000000..b0b1b80c9
--- /dev/null
+++ b/vendor/plugins/translate_routes/config/routes_es-ES.yml
@@ -0,0 +1 @@
+people: gente \ No newline at end of file
diff --git a/vendor/plugins/translate_routes/init.rb b/vendor/plugins/translate_routes/init.rb
new file mode 100755
index 000000000..9d09228c3
--- /dev/null
+++ b/vendor/plugins/translate_routes/init.rb
@@ -0,0 +1 @@
+require 'translate_routes' \ No newline at end of file
diff --git a/vendor/plugins/translate_routes/install.rb b/vendor/plugins/translate_routes/install.rb
new file mode 100755
index 000000000..f7732d379
--- /dev/null
+++ b/vendor/plugins/translate_routes/install.rb
@@ -0,0 +1 @@
+# Install hook code here
diff --git a/vendor/plugins/translate_routes/lib/translate_routes.rb b/vendor/plugins/translate_routes/lib/translate_routes.rb
new file mode 100755
index 000000000..1db92e90e
--- /dev/null
+++ b/vendor/plugins/translate_routes/lib/translate_routes.rb
@@ -0,0 +1,219 @@
+# Author: Raul Murciano [http://raul.murciano.net] for Domestika [http://domestika.org]
+# Copyright (c) 2007, Released under the MIT license (see MIT-LICENSE)
+
+module ActionController
+
+ module Routing
+
+ module Translator
+
+ mattr_accessor :prefix_on_default_locale
+ @@prefix_on_default_locale = false
+
+ mattr_accessor :locale_param_key
+ @@locale_param_key = :locale # set to :locale for params[:locale]
+
+ mattr_accessor :original_routes, :original_named_routes, :original_names, :dictionaries
+
+ def self.translate
+ init_dictionaries
+ yield @@dictionaries
+ @using_i18n = false
+ Translator.translate_current_routes
+ end
+
+ def self.translate_from_file(*path)
+ init_dictionaries
+ path = %w(locales routes.yml) if path.blank?
+ file_path = File.join(RAILS_ROOT, path)
+ yaml = YAML.load_file(file_path)
+ yaml.each_pair{ |k,v| @@dictionaries[k.to_s] = v || {} }
+ @using_i18n = false
+ Translator.translate_current_routes
+ end
+
+ def self.i18n(*locales)
+ init_dictionaries
+ locales = I18n.available_locales if locales.blank? && I18n.respond_to?(:available_locales)
+ locales.each{ |locale| @@dictionaries[locale] = {} }
+ @using_i18n = true
+ Translator.translate_current_routes
+ end
+
+ private
+
+ def self.default_locale
+ I18n.default_locale.to_s
+ end
+
+ def self.init_dictionaries
+ @@dictionaries = { default_locale => {} }
+ end
+
+ def self.available_locales
+ @@dictionaries.keys.map(&:to_s).uniq
+ end
+
+ def self.original_static_segments
+ static_segments = []
+ (@@original_routes || Routes.routes).each do |r|
+ r.segments.select do |s|
+ static_segments << s.value if s.instance_of?(ActionController::Routing::StaticSegment)
+ end
+ end
+ static_segments.uniq.sort
+ end
+
+ # code shared by translation and application helpers,
+ # it generates a suffix code for a given locale: en-US -> en_us
+ def self.locale_suffix_code
+ 'locale.to_s.underscore'
+ end
+
+ class_eval <<-FOO
+ def self.locale_suffix(locale)
+ #{self.locale_suffix_code}
+ end
+ FOO
+ def self.translate_current_routes
+
+ RAILS_DEFAULT_LOGGER.info "Translating routes (default locale: #{default_locale})" if defined? RAILS_DEFAULT_LOGGER
+
+ @@original_routes = Routes.routes.dup # Array [routeA, routeB, ...]
+ @@original_named_routes = Routes.named_routes.routes.dup # Hash {:name => :route}
+ @@original_names = @@original_named_routes.keys
+
+ Routes.clear!
+ new_routes = []
+ new_named_routes = {}
+
+ @@original_routes.each do |old_route|
+
+ old_name = @@original_named_routes.index(old_route)
+ # process and add the translated ones
+ trans_routes, trans_named_routes = translate_route(old_route, old_name)
+
+ if old_name
+ new_named_routes.merge! trans_named_routes
+ end
+
+ new_routes.concat(trans_routes)
+
+ end
+
+ Routes.routes = new_routes
+ new_named_routes.each { |name, r| Routes.named_routes.add name, r }
+
+ @@original_names.each{ |old_name| add_untranslated_helpers_to_controllers_and_views(old_name) }
+ end
+
+ # The untranslated helper (root_path instead root_en_path) redirects according to the current locale
+ def self.add_untranslated_helpers_to_controllers_and_views(old_name)
+
+ ['path', 'url'].each do |suffix|
+ new_helper_name = "#{old_name}_#{suffix}"
+ def_new_helper = <<-DEF_NEW_HELPER
+ def #{new_helper_name}(*args)
+ send("#{old_name}_\#{locale_suffix(I18n.locale)}_#{suffix}", *args)
+ end
+ DEF_NEW_HELPER
+
+ [ActionController::Base, ActionView::Base, ActionMailer::Base].each { |d| d.module_eval(def_new_helper) }
+ ActionController::Routing::Routes.named_routes.helpers << new_helper_name.to_sym
+ end
+ end
+
+ def self.add_prefix?(lang)
+ @@prefix_on_default_locale || lang != default_locale
+ end
+
+ def self.translate_static_segment(segment, locale)
+ if @using_i18n
+ tmp = I18n.locale
+ I18n.locale = locale
+ value = I18n.t segment.value, :default => segment.value.dup
+ I18n.locale = tmp
+ else
+ value = @@dictionaries[locale][segment.value] || segment.value.dup
+ end
+ StaticSegment.new(value, :raw => segment.raw, :optional => segment.optional?)
+ end
+
+ def self.locale_segments(orig, locale)
+ segments = []
+
+ if add_prefix?(locale) # initial prefix i.e: /en-US
+ divider = DividerSegment.new(orig.segments.first.value, :optional => false) # divider ('/')
+ static = StaticSegment.new(locale, :optional => false) # static ('en-US')
+ segments += [divider, static]
+ end
+
+ orig.segments.each do |s|
+ if s.instance_of?(StaticSegment)
+ new_segment = translate_static_segment(s, locale)
+ else
+ new_segment = s.dup # just reference the original
+ end
+ segments << new_segment
+ end
+ segments
+ end
+
+ def self.locale_requirements(orig, locale)
+ orig.requirements.merge(@@locale_param_key => locale)
+ end
+
+ def self.translate_route_by_locale(orig, locale, orig_name=nil)
+ segments = locale_segments(orig, locale)
+ requirements = locale_requirements(orig, locale)
+ conditions = orig.conditions
+
+ Route.new(segments, requirements, conditions).freeze
+ end
+
+ def self.root_route?(route)
+ route.segments.length == 1
+ end
+
+ def self.translate_route(route, route_name = nil)
+ new_routes = []
+ new_named_routes = {}
+
+ if root_route?(route) && prefix_on_default_locale
+ # add the root route "as is" in addition to the translated versions
+ new_routes << route
+ new_named_routes[route_name] = route
+ end
+
+ available_locales.each do |locale|
+ translated = translate_route_by_locale(route, locale, route_name)
+ new_routes << translated
+ locale_suffix = locale_suffix(locale)
+ new_named_routes["#{route_name}_#{locale_suffix}".to_sym] = translated if route_name
+ end
+ [new_routes, new_named_routes]
+ end
+
+ end
+
+ end
+end
+
+# Add set_locale_from_url to controllers
+ActionController::Base.class_eval do
+ private
+ def set_locale_from_url
+ I18n.locale = params[ActionController::Routing::Translator.locale_param_key]
+ default_url_options({ActionController::Routing::Translator => I18n.locale })
+ end
+end
+
+# Add locale_suffix to controllers, views and mailers
+[ActionController::Base, ActionView::Base, ActionMailer::Base].map do |klass|
+ klass.class_eval do
+ private
+ def locale_suffix(locale)
+ eval ActionController::Routing::Translator.locale_suffix_code
+ end
+ end
+end
diff --git a/vendor/plugins/translate_routes/lib/translate_routes_i18n_available_locales.rb b/vendor/plugins/translate_routes/lib/translate_routes_i18n_available_locales.rb
new file mode 100644
index 000000000..644483059
--- /dev/null
+++ b/vendor/plugins/translate_routes/lib/translate_routes_i18n_available_locales.rb
@@ -0,0 +1,23 @@
+# monkeypatch I18n to get the available locales
+# (not strictly needed to use translate_routes, but recommended anyway)
+module I18n
+ class << self
+ def available_locales
+ backend.available_locales
+ end
+ end
+
+ module Backend
+ class Simple
+ def available_locales
+ init_translations unless initialized?
+ translations.keys
+ end
+ end
+ end
+end
+
+# load translation files from RAILS_ROOT/locales
+[:rb, :yml].each do |format|
+ I18n.load_path = Dir[File.join(RAILS_ROOT, 'locales', '*.{rb,yml}') ]
+end \ No newline at end of file
diff --git a/vendor/plugins/translate_routes/lib/translate_routes_test_helper.rb b/vendor/plugins/translate_routes/lib/translate_routes_test_helper.rb
new file mode 100644
index 000000000..5f589de55
--- /dev/null
+++ b/vendor/plugins/translate_routes/lib/translate_routes_test_helper.rb
@@ -0,0 +1,33 @@
+# Author: Raul Murciano [http://raul.murciano.net] for Domestika [http://domestika.org]
+# Copyright (c) 2007, Released under the MIT license (see MIT-LICENSE)
+
+require 'test_help'
+
+# Include default lang on your test requests (test requests doesn't support default_url_options):
+ActionController::TestProcess.class_eval do
+ unless method_defined?(:process_without_default_language)
+ def process_with_default_language(action, parameters = nil, session = nil, flash = nil)
+ lang_pair = {:locale, I18n.default_locale.to_s}
+ parameters = lang_pair.merge(parameters) rescue lang_pair
+ process_without_default_language(action, parameters, session, flash)
+ end
+
+ alias :process_without_default_language :process
+ alias :process :process_with_default_language
+ end
+end
+
+# Add untranslated helper for named routes to integration tests
+ActionController::Integration::Session.class_eval do
+ ['path', 'url'].each do |suffix|
+ ActionController::Routing::Translator.original_names.each do |old_name|
+ new_helper_name = "#{old_name}_#{suffix}"
+ def_new_helper = <<-DEF_NEW_HELPER
+ def #{new_helper_name}(*args)
+ send("#{old_name}_#{ActionController::Routing::Translator.locale_suffix(I18n.default_locale)}_#{suffix}", *args)
+ end
+ DEF_NEW_HELPER
+ eval def_new_helper
+ end
+ end
+end
diff --git a/vendor/plugins/translate_routes/tasks/translate_routes_tasks.rake b/vendor/plugins/translate_routes/tasks/translate_routes_tasks.rake
new file mode 100755
index 000000000..f94d7c9e4
--- /dev/null
+++ b/vendor/plugins/translate_routes/tasks/translate_routes_tasks.rake
@@ -0,0 +1,38 @@
+config_path = File.expand_path(File.join(RAILS_ROOT, 'config'))
+require File.join(config_path, 'environment')
+
+namespace :translate_routes do
+
+ desc "Updates yaml translation files for the given languages"
+ task :update_yaml, :langs do |task, args|
+ segments = ActionController::Routing::Translator.original_static_segments
+
+ if args[:langs].is_a?(String)
+ langs = args[:langs] + ' ' + ActionController::Routing::Translator.default_locale
+ langs.split.uniq.each do |lang|
+
+ file_path = File.join(config_path, "routes_#{lang}.yml");
+
+ if File.exists?(file_path)
+ puts "Updating #{file_path}"
+ translations = YAML.load_file(file_path)
+ f = File.open(file_path,'w')
+ else
+ puts "Creating #{file_path}"
+ translations = {}
+ f = File.new(file_path, 'w')
+ end
+
+ f.write "#{lang}:\n"
+ segments.each do |s|
+ translation = translations[lang][s] rescue ''
+ f.write " #{s}: #{translation}\n"
+ end
+ f.close
+ end
+
+ else
+ puts 'Missing parameters, usage example: rake translate_routes:update_yaml["fr de es"]'
+ end
+ end
+end
diff --git a/vendor/plugins/translate_routes/test/locales/routes.yml b/vendor/plugins/translate_routes/test/locales/routes.yml
new file mode 100644
index 000000000..380949823
--- /dev/null
+++ b/vendor/plugins/translate_routes/test/locales/routes.yml
@@ -0,0 +1,5 @@
+es:
+ people: gente
+
+en:
+ \ No newline at end of file
diff --git a/vendor/plugins/translate_routes/test/translate_routes_test.rb b/vendor/plugins/translate_routes/test/translate_routes_test.rb
new file mode 100755
index 000000000..9b8a2dfcf
--- /dev/null
+++ b/vendor/plugins/translate_routes/test/translate_routes_test.rb
@@ -0,0 +1,323 @@
+require 'test/unit'
+require 'rubygems'
+
+%w(actionpack activesupport actionmailer).each{ |gem_lib| gem gem_lib, '2.2.2' }
+
+%w( activesupport actionpack actionmailer action_controller action_controller/test_case
+ action_controller/test_process action_controller/assertions
+ ).each{ |lib| require lib }
+
+plugin_root = File.join(File.dirname(__FILE__), '..')
+require "#{plugin_root}/lib/translate_routes"
+RAILS_ROOT = plugin_root
+
+class PeopleController < ActionController::Base; end
+
+class TranslateRoutesTest < Test::Unit::TestCase
+
+ def setup
+ @controller = ActionController::Base.new
+ @view = ActionView::Base.new
+ end
+
+
+ # Unnamed routes with prefix on default locale:
+
+ def test_unnamed_empty_route_with_prefix
+ ActionController::Routing::Routes.draw { |map| map.connect '', :controller => 'people', :action => 'index' }
+ config_default_locale_settings('en', true)
+ ActionController::Routing::Translator.translate { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
+
+ assert_routing '/es', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_routing '/en', :controller => 'people', :action => 'index', :locale => 'en'
+ end
+
+ def test_unnamed_root_route_with_prefix
+ ActionController::Routing::Routes.draw { |map| map.connect '/', :controller => 'people', :action => 'index'}
+ config_default_locale_settings('es', true)
+ ActionController::Routing::Translator.translate_from_file 'test', 'locales', 'routes.yml'
+
+ assert_routing '/', :controller => 'people', :action => 'index'
+ assert_routing '/es', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_routing '/en', :controller => 'people', :action => 'index', :locale => 'en'
+ end
+
+ def test_unnamed_untranslated_route_with_prefix
+ ActionController::Routing::Routes.draw { |map| map.connect 'foo', :controller => 'people', :action => 'index' }
+ config_default_locale_settings('en', true)
+ ActionController::Routing::Translator.translate { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
+
+ assert_routing '/es/foo', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_routing '/en/foo', :controller => 'people', :action => 'index', :locale => 'en'
+ end
+
+ def test_unnamed_translated_route_on_default_locale_with_prefix
+ ActionController::Routing::Routes.draw { |map| map.people 'people', :controller => 'people', :action => 'index'}
+ config_default_locale_settings('es', true)
+ ActionController::Routing::Translator.translate { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
+
+ assert_routing '/es/gente', :controller => 'people', :action => 'index', :locale => 'es'
+ end
+
+ def test_unnamed_translated_route_on_non_default_locale_with_prefix
+ ActionController::Routing::Routes.draw { |map| map.connect 'people', :controller => 'people', :action => 'index' }
+ config_default_locale_settings('en', true)
+ ActionController::Routing::Translator.translate { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
+
+ assert_routing '/es/gente', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_routing '/en/people', :controller => 'people', :action => 'index', :locale => 'en'
+ end
+
+
+ # Unnamed routes without prefix on default locale:
+
+ def test_unnamed_empty_route_without_prefix
+ ActionController::Routing::Routes.draw { |map| map.connect '', :controller => 'people', :action => 'index' }
+ config_default_locale_settings('en', false)
+ ActionController::Routing::Translator.translate { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
+
+ assert_routing '/es', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_routing '/', :controller => 'people', :action => 'index', :locale => 'en'
+ end
+
+ def test_unnamed_root_route_without_prefix
+ ActionController::Routing::Routes.draw { |map| map.connect '/', :controller => 'people', :action => 'index'}
+ config_default_locale_settings('es', false)
+ ActionController::Routing::Translator.translate_from_file 'test', 'locales', 'routes.yml'
+
+ assert_routing '/', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_routing '/en', :controller => 'people', :action => 'index', :locale => 'en'
+ assert_unrecognized_route '/es', :controller => 'people', :action => 'index', :locale => 'es'
+ end
+
+ def test_unnamed_untranslated_route_without_prefix
+ ActionController::Routing::Routes.draw { |map| map.connect 'foo', :controller => 'people', :action => 'index'}
+ config_default_locale_settings('en', false)
+ ActionController::Routing::Translator.translate { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
+
+ assert_routing '/es/foo', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_routing '/foo', :controller => 'people', :action => 'index', :locale => 'en'
+ end
+
+ def test_unnamed_translated_route_on_default_locale_without_prefix
+ ActionController::Routing::Routes.draw { |map| map.people 'people', :controller => 'people', :action => 'index'}
+ config_default_locale_settings('es', false)
+ ActionController::Routing::Translator.translate { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
+
+ assert_routing '/en/people', :controller => 'people', :action => 'index', :locale => 'en'
+ assert_routing 'gente', :controller => 'people', :action => 'index', :locale => 'es'
+ end
+
+ def test_unnamed_translated_route_on_non_default_locale_without_prefix
+ ActionController::Routing::Routes.draw { |map| map.people 'people', :controller => 'people', :action => 'index'}
+ config_default_locale_settings('en', false)
+ ActionController::Routing::Translator.translate { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
+
+ assert_routing '/es/gente', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_routing '/people', :controller => 'people', :action => 'index', :locale => 'en'
+ end
+
+
+ # Named routes with prefix on default locale:
+
+ def test_named_empty_route_with_prefix
+ ActionController::Routing::Routes.draw { |map| map.people '', :controller => 'people', :action => 'index' }
+ config_default_locale_settings('en', true)
+ ActionController::Routing::Translator.translate { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
+
+ assert_routing '/es', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_routing '/en', :controller => 'people', :action => 'index', :locale => 'en'
+ assert_helpers_include :people_en, :people_es, :people
+ end
+
+ def test_named_root_route_with_prefix
+ ActionController::Routing::Routes.draw { |map| map.root :controller => 'people', :action => 'index'}
+ config_default_locale_settings('es', true)
+ ActionController::Routing::Translator.translate_from_file 'test', 'locales', 'routes.yml'
+
+ assert_routing '/', :controller => 'people', :action => 'index'
+ assert_routing '/es', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_routing '/en', :controller => 'people', :action => 'index', :locale => 'en'
+ end
+
+ def test_named_untranslated_route_with_prefix
+ ActionController::Routing::Routes.draw { |map| map.people 'foo', :controller => 'people', :action => 'index'}
+ config_default_locale_settings('en', true)
+ ActionController::Routing::Translator.translate { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
+
+ assert_routing '/es/foo', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_routing '/en/foo', :controller => 'people', :action => 'index', :locale => 'en'
+ assert_helpers_include :people_en, :people_es, :people
+ end
+
+ def test_named_translated_route_on_default_locale_with_prefix
+ ActionController::Routing::Routes.draw { |map| map.people 'people', :controller => 'people', :action => 'index'}
+ config_default_locale_settings('es', true)
+ ActionController::Routing::Translator.translate { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
+
+ assert_routing '/en/people', :controller => 'people', :action => 'index', :locale => 'en'
+ assert_routing '/es/gente', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_helpers_include :people_en, :people_es, :people
+ end
+
+ def test_named_translated_route_on_non_default_locale_with_prefix
+ ActionController::Routing::Routes.draw { |map| map.people 'people', :controller => 'people', :action => 'index' }
+ config_default_locale_settings('en', true)
+ ActionController::Routing::Translator.translate { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
+
+ assert_routing '/es/gente', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_routing '/en/people', :controller => 'people', :action => 'index', :locale => 'en'
+ assert_helpers_include :people_en, :people_es, :people
+ end
+
+ # Named routes without prefix on default locale:
+
+ def test_named_empty_route_without_prefix
+ ActionController::Routing::Routes.draw { |map| map.people '', :controller => 'people', :action => 'index'}
+ config_default_locale_settings('es', false)
+ ActionController::Routing::Translator.translate { |t| t['es'] = {}; t['en'] = {'people' => 'gente'}; }
+
+ assert_routing '/en', :controller => 'people', :action => 'index', :locale => 'en'
+ assert_routing '/', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_routing '', :controller => 'people', :action => 'index', :locale => 'es'
+ end
+
+ def test_named_root_route_without_prefix
+ ActionController::Routing::Routes.draw { |map| map.root :controller => 'people', :action => 'index'}
+ config_default_locale_settings('es', false)
+ ActionController::Routing::Translator.translate_from_file 'test', 'locales', 'routes.yml'
+
+ assert_routing '/', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_routing '/en', :controller => 'people', :action => 'index', :locale => 'en'
+ assert_unrecognized_route '/es', :controller => 'people', :action => 'index', :locale => 'es'
+ end
+
+ def test_named_untranslated_route_without_prefix
+ ActionController::Routing::Routes.draw { |map| map.people 'foo', :controller => 'people', :action => 'index'}
+ config_default_locale_settings('es', false)
+ ActionController::Routing::Translator.translate { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
+
+ assert_routing '/en/foo', :controller => 'people', :action => 'index', :locale => 'en'
+ assert_routing 'foo', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_helpers_include :people_en, :people_es, :people
+ end
+
+ def test_named_translated_route_on_default_locale_without_prefix
+ ActionController::Routing::Routes.draw { |map| map.people 'people', :controller => 'people', :action => 'index'}
+ config_default_locale_settings('es', false)
+ ActionController::Routing::Translator.translate { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
+
+ assert_routing '/en/people', :controller => 'people', :action => 'index', :locale => 'en'
+ assert_routing 'gente', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_helpers_include :people_en, :people_es, :people
+ end
+
+ def test_named_translated_route_on_non_default_locale_without_prefix
+ ActionController::Routing::Routes.draw { |map| map.people 'people', :controller => 'people', :action => 'index'}
+ config_default_locale_settings('en', false)
+ ActionController::Routing::Translator.translate { |t| t['en'] = {}; t['es'] = {'people' => 'gente'} }
+
+ assert_routing '/people', :controller => 'people', :action => 'index', :locale => 'en'
+ assert_routing '/es/gente', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_helpers_include :people_en, :people_es, :people
+ end
+
+ def test_languages_load_from_file
+ ActionController::Routing::Routes.draw { |map| map.people 'people', :controller => 'people', :action => 'index'}
+ config_default_locale_settings('en', false)
+ ActionController::Routing::Translator.translate_from_file 'test', 'locales', 'routes.yml'
+
+ assert_routing '/people', :controller => 'people', :action => 'index', :locale => 'en'
+ assert_routing '/es/gente', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_helpers_include :people_en, :people_es, :people
+ end
+
+ def test_languages_load_from_file_without_dictionary_for_default_locale
+ ActionController::Routing::Routes.draw { |map| map.people 'people', :controller => 'people', :action => 'index'}
+ config_default_locale_settings('fr', false)
+ ActionController::Routing::Translator.translate_from_file 'test', 'locales', 'routes.yml'
+
+ assert_routing '/people', :controller => 'people', :action => 'index', :locale => 'fr'
+ assert_routing '/en/people', :controller => 'people', :action => 'index', :locale => 'en'
+ assert_routing '/es/gente', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_helpers_include :people_fr, :people_en, :people_es, :people
+ end
+
+ def test_i18n_based_translations_setting_locales
+ ActionController::Routing::Routes.draw { |map| map.people 'people', :controller => 'people', :action => 'index'}
+ config_default_locale_settings('en', false)
+ I18n.backend = StubbedI18nBackend
+ ActionController::Routing::Translator.i18n('es')
+
+ assert_routing '/people', :controller => 'people', :action => 'index', :locale => 'en'
+ assert_routing '/es/gente', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_helpers_include :people_en, :people_es, :people
+ end
+
+ def test_i18n_based_translations_taking_i18n_available_locales
+ ActionController::Routing::Routes.draw { |map| map.people 'people', :controller => 'people', :action => 'index'}
+ config_default_locale_settings('en', false)
+ I18n.stubs(:available_locales).at_least_once.returns StubbedI18nBackend.available_locales
+ I18n.backend = StubbedI18nBackend
+ ActionController::Routing::Translator.i18n
+
+ assert_routing '/people', :controller => 'people', :action => 'index', :locale => 'en'
+ assert_routing '/fr/people', :controller => 'people', :action => 'index', :locale => 'fr'
+ assert_routing '/es/gente', :controller => 'people', :action => 'index', :locale => 'es'
+ assert_helpers_include :people_fr, :people_en, :people_es, :people
+ end
+
+ def test_action_controller_gets_locale_setter
+ ActionController::Base.instance_methods.include?('set_locale_from_url')
+ end
+
+ def test_action_controller_gets_locale_suffix_helper
+ ActionController::Base.instance_methods.include?('locale_suffix')
+ end
+
+ def test_action_view_gets_locale_suffix_helper
+ ActionView::Base.instance_methods.include?('locale_suffix')
+ end
+
+ private
+
+ def assert_helpers_include(*helpers)
+ helpers.each do |helper|
+ ['_url', '_path'].each do |suffix|
+ [@controller, @view].each { |obj| assert_respond_to obj, "#{helper}#{suffix}".to_sym }
+ end
+ end
+ end
+
+ def assert_unrecognized_route(route_path, options)
+ assert_raise ActionController::RoutingError do
+ assert_routing route_path, options
+ end
+ end
+
+ def config_default_locale_settings(locale, with_prefix)
+ I18n.default_locale = locale
+ ActionController::Routing::Translator.prefix_on_default_locale = with_prefix
+ end
+
+ class StubbedI18nBackend
+
+
+ @@translations = {
+ 'es' => { 'people' => 'gente'},
+ 'fr' => {} # empty on purpose to test behaviour on incompleteness scenarios
+ }
+
+ def self.translate(locale, key, options)
+ @@translations[locale][key] || options[:default]
+ rescue
+ options[:default]
+ end
+
+ def self.available_locales
+ @@translations.keys
+ end
+
+ end
+
+end
diff --git a/vendor/plugins/translate_routes/uninstall.rb b/vendor/plugins/translate_routes/uninstall.rb
new file mode 100755
index 000000000..973833346
--- /dev/null
+++ b/vendor/plugins/translate_routes/uninstall.rb
@@ -0,0 +1 @@
+# Uninstall hook code here
diff --git a/vendor/rails-locales b/vendor/rails-locales
new file mode 160000
+Subproject d0fb0563129001c6114e351ba5738655733b833