diff options
105 files changed, 6076 insertions, 424 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/admin_public_body_controller.rb b/app/controllers/admin_public_body_controller.rb index 1b79642d2..3e0613a1f 100644 --- a/app/controllers/admin_public_body_controller.rb +++ b/app/controllers/admin_public_body_controller.rb @@ -13,19 +13,22 @@ class AdminPublicBodyController < AdminController end def _lookup_query_internal - @query = params[:query] - if @query == "" - @query = nil - end - @page = params[:page] - if @page == "" - @page = nil + @locale = self.locale_from_params() + PublicBody.with_locale(@locale) do + @query = params[:query] + if @query == "" + @query = nil + end + @page = params[:page] + if @page == "" + @page = nil + end + @public_bodies = PublicBody.paginate :order => "name", :page => @page, :per_page => 100, + :conditions => @query.nil? ? nil : ["lower(name) like lower('%'||?||'%') or + lower(short_name) like lower('%'||?||'%') or + lower(request_email) like lower('%'||?||'%')", @query, @query, @query] + @public_bodies_by_tag = PublicBody.find_by_tag(@query) end - @public_bodies = PublicBody.paginate :order => "name", :page => @page, :per_page => 100, - :conditions => @query.nil? ? nil : ["lower(name) like lower('%'||?||'%') or - lower(short_name) like lower('%'||?||'%') or - lower(request_email) like lower('%'||?||'%')", @query, @query, @query] - @public_bodies_by_tag = PublicBody.find_by_tag(@query) end def list @@ -69,51 +72,69 @@ class AdminPublicBodyController < AdminController end def show - @public_body = PublicBody.find(params[:id]) + @locale = self.locale_from_params() + PublicBody.with_locale(@locale) do + @public_body = PublicBody.find(params[:id]) + end end def new - @public_body = PublicBody.new + @locale = self.locale_from_params() + PublicBody.with_locale(@locale) do + @public_body = PublicBody.new + end end def create - params[:public_body][:last_edit_editor] = admin_http_auth_user() - @public_body = PublicBody.new(params[:public_body]) - if @public_body.save - flash[:notice] = 'PublicBody was successfully created.' - redirect_to admin_url('body/show/' + @public_body.id.to_s) - else - render :action => 'new' + @locale = self.locale_from_params() + PublicBody.with_locale(@locale) do + params[:public_body][:last_edit_editor] = admin_http_auth_user() + @public_body = PublicBody.new(params[:public_body]) + if @public_body.save + flash[:notice] = 'PublicBody was successfully created.' + redirect_to admin_url('body/show/' + @public_body.id.to_s) + else + render :action => 'new' + end end end def edit - @public_body = PublicBody.find(params[:id]) - @public_body.last_edit_comment = "" + @locale = self.locale_from_params() + PublicBody.with_locale(@locale) do + @public_body = PublicBody.find(params[:id]) + @public_body.last_edit_comment = "" + end end def update - params[:public_body][:last_edit_editor] = admin_http_auth_user() - @public_body = PublicBody.find(params[:id]) - if @public_body.update_attributes(params[:public_body]) - flash[:notice] = 'PublicBody was successfully updated.' - redirect_to admin_url('body/show/' + @public_body.id.to_s) - else - render :action => 'edit' + @locale = self.locale_from_params() + PublicBody.with_locale(@locale) do + params[:public_body][:last_edit_editor] = admin_http_auth_user() + @public_body = PublicBody.find(params[:id]) + if @public_body.update_attributes(params[:public_body]) + flash[:notice] = 'PublicBody was successfully updated.' + redirect_to admin_url('body/show/' + @public_body.id.to_s) + else + render :action => 'edit' + end end end def destroy - public_body = PublicBody.find(params[:id]) + @locale = self.locale_from_params() + PublicBody.with_locale(@locale) do + public_body = PublicBody.find(params[:id]) + + if public_body.info_requests.size > 0 + flash[:notice] = "There are requests associated with the authority, so can't destroy it" + redirect_to admin_url('body/show/' + public_body.id.to_s) + return + end - if public_body.info_requests.size > 0 - flash[:notice] = "There are requests associated with the authority, so can't destroy it" - redirect_to admin_url('body/show/' + public_body.id.to_s) - return + public_body.tag_string = "" + public_body.destroy end - - public_body.tag_string = "" - public_body.destroy flash[:notice] = "PublicBody was successfully destroyed." redirect_to admin_url('body/list') end 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/controllers/request_controller.rb b/app/controllers/request_controller.rb index 36fbc2b11..02abc12a8 100644 --- a/app/controllers/request_controller.rb +++ b/app/controllers/request_controller.rb @@ -11,69 +11,73 @@ class RequestController < ApplicationController protect_from_forgery :only => [ :new, :show_response, :describe_state, :upload_response ] # See ActionController::RequestForgeryProtection for details def show - # Look up by old style numeric identifiers - if params[:url_title].match(/^[0-9]+$/) - @info_request = InfoRequest.find(params[:url_title].to_i) - redirect_to request_url(@info_request) - return - end + @locale = self.locale_from_params() + PublicBody.with_locale(@locale) do - # Look up by new style text names - @info_request = InfoRequest.find_by_url_title(params[:url_title]) - if @info_request.nil? - raise "Request not found" - end - set_last_request(@info_request) + # Look up by old style numeric identifiers + if params[:url_title].match(/^[0-9]+$/) + @info_request = InfoRequest.find(params[:url_title].to_i) + redirect_to request_url(@info_request) + return + end - # Test for whole request being hidden - if !@info_request.user_can_view?(authenticated_user) - render :template => 'request/hidden', :status => 410 # gone - return - end - - # Other parameters - @info_request_events = @info_request.info_request_events - @status = @info_request.calculate_status - @collapse_quotes = params[:unfold] ? false : true - @update_status = params[:update_status] ? true : false - @is_owning_user = @info_request.is_owning_user?(authenticated_user) - @old_unclassified = @info_request.is_old_unclassified? && !authenticated_user.nil? - - if @update_status - return if !@is_owning_user && !authenticated_as_user?(@info_request.user, - :web => "To update the status of this FOI request", - :email => "Then you can update the status of your request to " + @info_request.public_body.name + ".", - :email_subject => "Update the status of your request to " + @info_request.public_body.name - ) - end - - @last_info_request_event_id = @info_request.last_event_id_needing_description - @new_responses_count = @info_request.events_needing_description.select {|i| i.event_type == 'response'}.size - - # Sidebar stuff - # ... requests that have similar imporant terms - behavior_cache :tag => ['similar', @info_request.id] do - begin - limit = 10 - @xapian_similar = ::ActsAsXapian::Similar.new([InfoRequestEvent], @info_request.info_request_events, - :limit => limit, :collapse_by_prefix => 'request_collapse') - @xapian_similar_more = (@xapian_similar.matches_estimated > limit) - rescue - @xapian_similar = nil + # Look up by new style text names + @info_request = InfoRequest.find_by_url_title(params[:url_title]) + if @info_request.nil? + raise "Request not found" end - end - - # Track corresponding to this page - @track_thing = TrackThing.create_track_for_request(@info_request) - @feed_autodetect = [ { :url => do_track_url(@track_thing, 'feed'), :title => @track_thing.params[:title_in_rss], :has_json => true } ] + set_last_request(@info_request) - # For send followup link at bottom - @last_response = @info_request.get_last_response + # Test for whole request being hidden + if !@info_request.user_can_view?(authenticated_user) + render :template => 'request/hidden', :status => 410 # gone + return + end + + # Other parameters + @info_request_events = @info_request.info_request_events + @status = @info_request.calculate_status + @collapse_quotes = params[:unfold] ? false : true + @update_status = params[:update_status] ? true : false + @is_owning_user = @info_request.is_owning_user?(authenticated_user) + @old_unclassified = @info_request.is_old_unclassified? && !authenticated_user.nil? + + if @update_status + return if !@is_owning_user && !authenticated_as_user?(@info_request.user, + :web => "To update the status of this FOI request", + :email => "Then you can update the status of your request to " + @info_request.public_body.name + ".", + :email_subject => "Update the status of your request to " + @info_request.public_body.name + ) + end + + @last_info_request_event_id = @info_request.last_event_id_needing_description + @new_responses_count = @info_request.events_needing_description.select {|i| i.event_type == 'response'}.size + + # Sidebar stuff + # ... requests that have similar imporant terms + behavior_cache :tag => ['similar', @info_request.id] do + begin + limit = 10 + @xapian_similar = ::ActsAsXapian::Similar.new([InfoRequestEvent], @info_request.info_request_events, + :limit => limit, :collapse_by_prefix => 'request_collapse') + @xapian_similar_more = (@xapian_similar.matches_estimated > limit) + rescue + @xapian_similar = nil + end + end + + # Track corresponding to this page + @track_thing = TrackThing.create_track_for_request(@info_request) + @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 => @info_request.json_for_api(true) } - end + # For send followup link at bottom + @last_response = @info_request.get_last_response + + respond_to do |format| + format.html { @has_json = true } + format.json { render :json => @info_request.json_for_api(true) } + end + end end # Extra info about a request, such as event history @@ -666,28 +670,30 @@ class RequestController < ApplicationController # FOI officers can upload a response def upload_response - @info_request = InfoRequest.find_by_url_title(params[:url_title]) - - @reason_params = { - :web => "To upload a response, you must be logged in using an email address from " + CGI.escapeHTML(@info_request.public_body.name), - :email => "Then you can upload an FOI response. ", - :email_subject => "Confirm your account on WhatDoTheyKnow.com" - } - if !authenticated?(@reason_params) - return - end + @locale = self.locale_from_params() + PublicBody.with_locale(@locale) do + @info_request = InfoRequest.find_by_url_title(params[:url_title]) + + @reason_params = { + :web => "To upload a response, you must be logged in using an email address from " + CGI.escapeHTML(@info_request.public_body.name), + :email => "Then you can upload an FOI response. ", + :email_subject => "Confirm your account on WhatDoTheyKnow.com" + } + if !authenticated?(@reason_params) + return + end - if !@info_request.public_body.is_foi_officer?(@user) - domain_required = @info_request.public_body.foi_officer_domain_required - if domain_required.nil? - render :template => 'user/wrong_user_unknown_email' + if !@info_request.public_body.is_foi_officer?(@user) + domain_required = @info_request.public_body.foi_officer_domain_required + if domain_required.nil? + render :template => 'user/wrong_user_unknown_email' + return + end + @reason_params[:user_name] = "an email @" + domain_required + render :template => 'user/wrong_user' return end - @reason_params[:user_name] = "an email @" + domain_required - render :template => 'user/wrong_user' - return end - if params[:submitted_upload_response] file_name = nil file_content = nil 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 %> - <a href="/search">Advanced search tips</a> + <%= 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 – <small>a message from WhatDoTheyKnow</small></h2> - <p>Sorry to interrupt, but we thought you’d like to know that <strong>you won</strong>! - <p>On the 16th of May 2008 the High Court ruled that MPs’ 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 – - <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>“And - those of us who manage the public’s dollars will be held to account – to - spend wisely, reform bad habits, and do our business in the light of day – - - because only then can we restore the vital trust between a people and their - government.”</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 ec7f61ec1..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') @@ -19,6 +19,7 @@ $:.push(File.join(File.dirname(__FILE__), '../commonlib/rblib')) # ruby-ole and ruby-msg. We use a custom ruby-msg to avoid a name conflict $:.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/general-example b/config/general-example index 4a1f88ccc..29f29ca8d 100644 --- a/config/general-example +++ b/config/general-example @@ -54,4 +54,6 @@ define('OPTION_READ_ONLY', ''); define('OPTION_RECAPTCHA_PUBLIC_KEY', 'x'); define('OPTION_RECAPTCHA_PRIVATE_KEY', 'x'); +// Locales we wish to support in this app +define('OPTION_AVAILABLE_LOCALES', 'en es') ?> 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/development_structure.sql b/db/development_structure.sql index 1dd93901b..d9ce53380 100644 --- a/db/development_structure.sql +++ b/db/development_structure.sql @@ -95,7 +95,8 @@ CREATE TABLE comments ( body text NOT NULL, visible boolean DEFAULT true NOT NULL, created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + updated_at timestamp without time zone NOT NULL, + locale text DEFAULT ''::text NOT NULL ); @@ -508,6 +509,45 @@ ALTER SEQUENCE public_body_tags_id_seq OWNED BY has_tag_string_tags.id; -- +-- Name: public_body_translations; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE public_body_translations ( + id integer NOT NULL, + public_body_id integer, + locale character varying(255), + short_name text, + request_email text, + notes text, + publication_scheme text, + url_name text, + first_letter character varying(255), + name text, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: public_body_translations_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public_body_translations_id_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- Name: public_body_translations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public_body_translations_id_seq OWNED BY public_body_translations.id; + + +-- -- Name: public_body_versions; Type: TABLE; Schema: public; Owner: -; Tablespace: -- @@ -832,6 +872,13 @@ ALTER TABLE public_bodies ALTER COLUMN id SET DEFAULT nextval('public_bodies_id_ -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- +ALTER TABLE public_body_translations ALTER COLUMN id SET DEFAULT nextval('public_body_translations_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + ALTER TABLE public_body_versions ALTER COLUMN id SET DEFAULT nextval('public_body_versions_id_seq'::regclass); @@ -983,6 +1030,14 @@ ALTER TABLE ONLY has_tag_string_tags -- +-- Name: public_body_translations_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY public_body_translations + ADD CONSTRAINT public_body_translations_pkey PRIMARY KEY (id); + + +-- -- Name: public_body_versions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- @@ -1192,6 +1247,13 @@ CREATE UNIQUE INDEX index_public_body_tags_on_public_body_id_and_name_and_value -- +-- Name: index_public_body_translations_on_public_body_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_public_body_translations_on_public_body_id ON public_body_translations USING btree (public_body_id); + + +-- -- Name: index_track_things_on_tracking_user_id_and_track_query; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -1248,30 +1310,6 @@ CREATE INDEX users_lower_email_index ON users USING btree (lower((email)::text)) -- --- Name: fk_censor_rules_info_request; Type: FK CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY censor_rules - ADD CONSTRAINT fk_censor_rules_info_request FOREIGN KEY (info_request_id) REFERENCES info_requests(id); - - --- --- Name: fk_censor_rules_public_body; Type: FK CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY censor_rules - ADD CONSTRAINT fk_censor_rules_public_body FOREIGN KEY (public_body_id) REFERENCES public_bodies(id); - - --- --- Name: fk_censor_rules_user; Type: FK CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY censor_rules - ADD CONSTRAINT fk_censor_rules_user FOREIGN KEY (user_id) REFERENCES users(id); - - --- -- Name: fk_comments_info_request; Type: FK CONSTRAINT; Schema: public; Owner: - -- @@ -1673,4 +1711,8 @@ INSERT INTO schema_migrations (version) VALUES ('93'); INSERT INTO schema_migrations (version) VALUES ('94'); -INSERT INTO schema_migrations (version) VALUES ('95');
\ No newline at end of file +INSERT INTO schema_migrations (version) VALUES ('95'); + +INSERT INTO schema_migrations (version) VALUES ('96'); + +INSERT INTO schema_migrations (version) VALUES ('97');
\ No newline at end of file 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..d27fbe815 100644 --- a/locale/app.pot +++ b/locale/app.pot @@ -7,30 +7,418 @@ 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-31 08:59+0100\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 "" + +#: locale/model_attributes.rb:46 +msgid "CensorRule|Last edit comment" +msgstr "" + +#: locale/model_attributes.rb:45 +msgid "CensorRule|Last edit editor" +msgstr "" + +#: locale/model_attributes.rb:44 +msgid "CensorRule|Replacement" +msgstr "" + +#: locale/model_attributes.rb:43 +msgid "CensorRule|Text" +msgstr "" + +#: app/views/public_body/show.rhtml:17 app/views/public_body/show.rhtml:19 +msgid "Charity registration" +msgstr "" + +#: locale/model_attributes.rb:22 +msgid "Comment|Body" +msgstr "" + +#: locale/model_attributes.rb:21 +msgid "Comment|Comment type" +msgstr "" + +#: locale/model_attributes.rb:24 +msgid "Comment|Locale" +msgstr "" + +#: locale/model_attributes.rb:23 +msgid "Comment|Visible" +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 "" + +#: locale/model_attributes.rb:61 +msgid "EximLogDone|Filename" +msgstr "" + +#: locale/model_attributes.rb:62 +msgid "EximLogDone|Last stat" +msgstr "" + +#: locale/model_attributes.rb:19 +msgid "EximLog|Line" +msgstr "" + +#: locale/model_attributes.rb:18 +msgid "EximLog|Order" +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 "" + +#: locale/model_attributes.rb:58 +msgid "Holiday|Day" +msgstr "" + +#: locale/model_attributes.rb:59 +msgid "Holiday|Description" +msgstr "" + +#: app/views/public_body/show.rhtml:8 +msgid "Home page of authority" +msgstr "" + +#: locale/model_attributes.rb:64 +msgid "IncomingMessage|Cached attachment text clipped" +msgstr "" + +#: locale/model_attributes.rb:65 +msgid "IncomingMessage|Cached main body text folded" +msgstr "" + +#: locale/model_attributes.rb:66 +msgid "IncomingMessage|Cached main body text unfolded" +msgstr "" + +#: locale/model_attributes.rb:39 +msgid "InfoRequestEvent|Calculated state" +msgstr "" + +#: locale/model_attributes.rb:38 +msgid "InfoRequestEvent|Described state" +msgstr "" + +#: locale/model_attributes.rb:36 +msgid "InfoRequestEvent|Event type" +msgstr "" + +#: locale/model_attributes.rb:40 +msgid "InfoRequestEvent|Last described at" +msgstr "" + +#: locale/model_attributes.rb:37 +msgid "InfoRequestEvent|Params yaml" +msgstr "" + +#: locale/model_attributes.rb:41 +msgid "InfoRequestEvent|Prominence" +msgstr "" + +#: locale/model_attributes.rb:87 +msgid "InfoRequest|Allow new responses from" +msgstr "" + +#: locale/model_attributes.rb:83 +msgid "InfoRequest|Awaiting description" +msgstr "" + +#: locale/model_attributes.rb:82 +msgid "InfoRequest|Described state" +msgstr "" + +#: locale/model_attributes.rb:88 +msgid "InfoRequest|Handle rejected responses" +msgstr "" + +#: locale/model_attributes.rb:86 +msgid "InfoRequest|Law used" +msgstr "" + +#: locale/model_attributes.rb:84 +msgid "InfoRequest|Prominence" +msgstr "" + +#: locale/model_attributes.rb:81 +msgid "InfoRequest|Title" +msgstr "" + +#: locale/model_attributes.rb:85 +msgid "InfoRequest|Url title" +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 "" + +#: locale/model_attributes.rb:26 +msgid "OutgoingMessage|Body" +msgstr "" + +#: locale/model_attributes.rb:29 +msgid "OutgoingMessage|Last sent at" +msgstr "" + +#: locale/model_attributes.rb:28 +msgid "OutgoingMessage|Message type" +msgstr "" + +#: locale/model_attributes.rb:27 +msgid "OutgoingMessage|Status" +msgstr "" + +#: locale/model_attributes.rb:30 +msgid "OutgoingMessage|What doing" +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 +537,335 @@ msgid "" "This makes it easier for others to read." msgstr "" -msgid "activerecord.errors.full_messages.format" -msgstr "%{message}" +#: locale/model_attributes.rb:56 +msgid "PostRedirect|Circumstance" +msgstr "" + +#: locale/model_attributes.rb:54 +msgid "PostRedirect|Email token" +msgstr "" + +#: locale/model_attributes.rb:53 +msgid "PostRedirect|Post params yaml" +msgstr "" + +#: locale/model_attributes.rb:55 +msgid "PostRedirect|Reason params yaml" +msgstr "" + +#: locale/model_attributes.rb:51 +msgid "PostRedirect|Token" +msgstr "" + +#: locale/model_attributes.rb:52 +msgid "PostRedirect|Uri" +msgstr "" + +#: locale/model_attributes.rb:15 +msgid "ProfilePhoto|Data" +msgstr "" + +#: locale/model_attributes.rb:16 +msgid "ProfilePhoto|Draft" +msgstr "" + +#: app/views/general/search.rhtml:70 +msgid "" +"Public authorities {{start_count}} to {{end_count}} of {{total_count}} for " +"{{user_search_query}}" +msgstr "" + +#: locale/model_attributes.rb:12 +msgid "PublicBody|First letter" +msgstr "" + +#: locale/model_attributes.rb:10 +msgid "PublicBody|Home page" +msgstr "" + +#: locale/model_attributes.rb:8 +msgid "PublicBody|Last edit comment" +msgstr "" + +#: locale/model_attributes.rb:7 +msgid "PublicBody|Last edit editor" +msgstr "" + +#: locale/model_attributes.rb:3 +msgid "PublicBody|Name" +msgstr "" + +#: locale/model_attributes.rb:11 +msgid "PublicBody|Notes" +msgstr "" + +#: locale/model_attributes.rb:13 +msgid "PublicBody|Publication scheme" +msgstr "" + +#: locale/model_attributes.rb:5 +msgid "PublicBody|Request email" +msgstr "" + +#: locale/model_attributes.rb:4 +msgid "PublicBody|Short name" +msgstr "" + +#: locale/model_attributes.rb:9 +msgid "PublicBody|Url name" +msgstr "" + +#: locale/model_attributes.rb:6 +msgid "PublicBody|Version" +msgstr "" + +#: app/views/public_body/show.rhtml:11 +msgid "Publication scheme" +msgstr "" + +#: locale/model_attributes.rb:49 +msgid "RawEmail|Data binary" +msgstr "" + +#: locale/model_attributes.rb:48 +msgid "RawEmail|Data text" +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 "" + +#: locale/model_attributes.rb:33 +msgid "TrackThing|Track medium" +msgstr "" + +#: locale/model_attributes.rb:32 +msgid "TrackThing|Track query" +msgstr "" + +#: locale/model_attributes.rb:34 +msgid "TrackThing|Track type" +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 "" + +#: locale/model_attributes.rb:68 +msgid "UserInfoRequestSentAlert|Alert type" +msgstr "" + +#: locale/model_attributes.rb:79 +msgid "User|About me" +msgstr "" + +#: locale/model_attributes.rb:77 +msgid "User|Admin level" +msgstr "" + +#: locale/model_attributes.rb:78 +msgid "User|Ban text" +msgstr "" + +#: locale/model_attributes.rb:70 +msgid "User|Email" +msgstr "" + +#: locale/model_attributes.rb:74 +msgid "User|Email confirmed" +msgstr "" + +#: locale/model_attributes.rb:72 +msgid "User|Hashed password" +msgstr "" + +#: locale/model_attributes.rb:76 +msgid "User|Last daily track email" +msgstr "" + +#: locale/model_attributes.rb:71 +msgid "User|Name" +msgstr "" + +#: locale/model_attributes.rb:73 +msgid "User|Salt" +msgstr "" + +#: locale/model_attributes.rb:75 +msgid "User|Url name" +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 "" + +#: locale/model_attributes.rb:42 +msgid "censor rule" +msgstr "" + +#: locale/model_attributes.rb:20 +msgid "comment" +msgstr "" + +#: app/views/general/frontpage.rhtml:18 +msgid "e.g." +msgstr "" + +#: locale/model_attributes.rb:17 +msgid "exim log" +msgstr "" + +#: locale/model_attributes.rb:60 +msgid "exim log done" +msgstr "" + +#: locale/model_attributes.rb:57 +msgid "holiday" +msgstr "" + +#: locale/model_attributes.rb:63 +msgid "incoming message" +msgstr "" + +#: locale/model_attributes.rb:80 +msgid "info request" +msgstr "" + +#: locale/model_attributes.rb:35 +msgid "info request event" +msgstr "" + +#: locale/model_attributes.rb:25 +msgid "outgoing message" +msgstr "" + +#: locale/model_attributes.rb:50 +msgid "post redirect" +msgstr "" + +#: locale/model_attributes.rb:14 +msgid "profile photo" +msgstr "" + +#: locale/model_attributes.rb:2 +msgid "public body" +msgstr "" + +#: locale/model_attributes.rb:47 +msgid "raw email" +msgstr "" + +#: locale/model_attributes.rb:31 +msgid "track thing" +msgstr "" + +#: locale/model_attributes.rb:69 +msgid "user" +msgstr "" + +#: locale/model_attributes.rb:67 +msgid "user info request sent alert" +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..d27fbe815 100644 --- a/locale/en/app.po +++ b/locale/en/app.po @@ -7,30 +7,418 @@ 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-31 08:59+0100\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 "" + +#: locale/model_attributes.rb:46 +msgid "CensorRule|Last edit comment" +msgstr "" + +#: locale/model_attributes.rb:45 +msgid "CensorRule|Last edit editor" +msgstr "" + +#: locale/model_attributes.rb:44 +msgid "CensorRule|Replacement" +msgstr "" + +#: locale/model_attributes.rb:43 +msgid "CensorRule|Text" +msgstr "" + +#: app/views/public_body/show.rhtml:17 app/views/public_body/show.rhtml:19 +msgid "Charity registration" +msgstr "" + +#: locale/model_attributes.rb:22 +msgid "Comment|Body" +msgstr "" + +#: locale/model_attributes.rb:21 +msgid "Comment|Comment type" +msgstr "" + +#: locale/model_attributes.rb:24 +msgid "Comment|Locale" +msgstr "" + +#: locale/model_attributes.rb:23 +msgid "Comment|Visible" +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 "" + +#: locale/model_attributes.rb:61 +msgid "EximLogDone|Filename" +msgstr "" + +#: locale/model_attributes.rb:62 +msgid "EximLogDone|Last stat" +msgstr "" + +#: locale/model_attributes.rb:19 +msgid "EximLog|Line" +msgstr "" + +#: locale/model_attributes.rb:18 +msgid "EximLog|Order" +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 "" + +#: locale/model_attributes.rb:58 +msgid "Holiday|Day" +msgstr "" + +#: locale/model_attributes.rb:59 +msgid "Holiday|Description" +msgstr "" + +#: app/views/public_body/show.rhtml:8 +msgid "Home page of authority" +msgstr "" + +#: locale/model_attributes.rb:64 +msgid "IncomingMessage|Cached attachment text clipped" +msgstr "" + +#: locale/model_attributes.rb:65 +msgid "IncomingMessage|Cached main body text folded" +msgstr "" + +#: locale/model_attributes.rb:66 +msgid "IncomingMessage|Cached main body text unfolded" +msgstr "" + +#: locale/model_attributes.rb:39 +msgid "InfoRequestEvent|Calculated state" +msgstr "" + +#: locale/model_attributes.rb:38 +msgid "InfoRequestEvent|Described state" +msgstr "" + +#: locale/model_attributes.rb:36 +msgid "InfoRequestEvent|Event type" +msgstr "" + +#: locale/model_attributes.rb:40 +msgid "InfoRequestEvent|Last described at" +msgstr "" + +#: locale/model_attributes.rb:37 +msgid "InfoRequestEvent|Params yaml" +msgstr "" + +#: locale/model_attributes.rb:41 +msgid "InfoRequestEvent|Prominence" +msgstr "" + +#: locale/model_attributes.rb:87 +msgid "InfoRequest|Allow new responses from" +msgstr "" + +#: locale/model_attributes.rb:83 +msgid "InfoRequest|Awaiting description" +msgstr "" + +#: locale/model_attributes.rb:82 +msgid "InfoRequest|Described state" +msgstr "" + +#: locale/model_attributes.rb:88 +msgid "InfoRequest|Handle rejected responses" +msgstr "" + +#: locale/model_attributes.rb:86 +msgid "InfoRequest|Law used" +msgstr "" + +#: locale/model_attributes.rb:84 +msgid "InfoRequest|Prominence" +msgstr "" + +#: locale/model_attributes.rb:81 +msgid "InfoRequest|Title" +msgstr "" + +#: locale/model_attributes.rb:85 +msgid "InfoRequest|Url title" +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 "" + +#: locale/model_attributes.rb:26 +msgid "OutgoingMessage|Body" +msgstr "" + +#: locale/model_attributes.rb:29 +msgid "OutgoingMessage|Last sent at" +msgstr "" + +#: locale/model_attributes.rb:28 +msgid "OutgoingMessage|Message type" +msgstr "" + +#: locale/model_attributes.rb:27 +msgid "OutgoingMessage|Status" +msgstr "" + +#: locale/model_attributes.rb:30 +msgid "OutgoingMessage|What doing" +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 +537,335 @@ msgid "" "This makes it easier for others to read." msgstr "" -msgid "activerecord.errors.full_messages.format" -msgstr "%{message}" +#: locale/model_attributes.rb:56 +msgid "PostRedirect|Circumstance" +msgstr "" + +#: locale/model_attributes.rb:54 +msgid "PostRedirect|Email token" +msgstr "" + +#: locale/model_attributes.rb:53 +msgid "PostRedirect|Post params yaml" +msgstr "" + +#: locale/model_attributes.rb:55 +msgid "PostRedirect|Reason params yaml" +msgstr "" + +#: locale/model_attributes.rb:51 +msgid "PostRedirect|Token" +msgstr "" + +#: locale/model_attributes.rb:52 +msgid "PostRedirect|Uri" +msgstr "" + +#: locale/model_attributes.rb:15 +msgid "ProfilePhoto|Data" +msgstr "" + +#: locale/model_attributes.rb:16 +msgid "ProfilePhoto|Draft" +msgstr "" + +#: app/views/general/search.rhtml:70 +msgid "" +"Public authorities {{start_count}} to {{end_count}} of {{total_count}} for " +"{{user_search_query}}" +msgstr "" + +#: locale/model_attributes.rb:12 +msgid "PublicBody|First letter" +msgstr "" + +#: locale/model_attributes.rb:10 +msgid "PublicBody|Home page" +msgstr "" + +#: locale/model_attributes.rb:8 +msgid "PublicBody|Last edit comment" +msgstr "" + +#: locale/model_attributes.rb:7 +msgid "PublicBody|Last edit editor" +msgstr "" + +#: locale/model_attributes.rb:3 +msgid "PublicBody|Name" +msgstr "" + +#: locale/model_attributes.rb:11 +msgid "PublicBody|Notes" +msgstr "" + +#: locale/model_attributes.rb:13 +msgid "PublicBody|Publication scheme" +msgstr "" + +#: locale/model_attributes.rb:5 +msgid "PublicBody|Request email" +msgstr "" + +#: locale/model_attributes.rb:4 +msgid "PublicBody|Short name" +msgstr "" + +#: locale/model_attributes.rb:9 +msgid "PublicBody|Url name" +msgstr "" + +#: locale/model_attributes.rb:6 +msgid "PublicBody|Version" +msgstr "" + +#: app/views/public_body/show.rhtml:11 +msgid "Publication scheme" +msgstr "" + +#: locale/model_attributes.rb:49 +msgid "RawEmail|Data binary" +msgstr "" + +#: locale/model_attributes.rb:48 +msgid "RawEmail|Data text" +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 "" + +#: locale/model_attributes.rb:33 +msgid "TrackThing|Track medium" +msgstr "" + +#: locale/model_attributes.rb:32 +msgid "TrackThing|Track query" +msgstr "" + +#: locale/model_attributes.rb:34 +msgid "TrackThing|Track type" +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 "" + +#: locale/model_attributes.rb:68 +msgid "UserInfoRequestSentAlert|Alert type" +msgstr "" + +#: locale/model_attributes.rb:79 +msgid "User|About me" +msgstr "" + +#: locale/model_attributes.rb:77 +msgid "User|Admin level" +msgstr "" + +#: locale/model_attributes.rb:78 +msgid "User|Ban text" +msgstr "" + +#: locale/model_attributes.rb:70 +msgid "User|Email" +msgstr "" + +#: locale/model_attributes.rb:74 +msgid "User|Email confirmed" +msgstr "" + +#: locale/model_attributes.rb:72 +msgid "User|Hashed password" +msgstr "" + +#: locale/model_attributes.rb:76 +msgid "User|Last daily track email" +msgstr "" + +#: locale/model_attributes.rb:71 +msgid "User|Name" +msgstr "" + +#: locale/model_attributes.rb:73 +msgid "User|Salt" +msgstr "" + +#: locale/model_attributes.rb:75 +msgid "User|Url name" +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 "" + +#: locale/model_attributes.rb:42 +msgid "censor rule" +msgstr "" + +#: locale/model_attributes.rb:20 +msgid "comment" +msgstr "" + +#: app/views/general/frontpage.rhtml:18 +msgid "e.g." +msgstr "" + +#: locale/model_attributes.rb:17 +msgid "exim log" +msgstr "" + +#: locale/model_attributes.rb:60 +msgid "exim log done" +msgstr "" + +#: locale/model_attributes.rb:57 +msgid "holiday" +msgstr "" + +#: locale/model_attributes.rb:63 +msgid "incoming message" +msgstr "" + +#: locale/model_attributes.rb:80 +msgid "info request" +msgstr "" + +#: locale/model_attributes.rb:35 +msgid "info request event" +msgstr "" + +#: locale/model_attributes.rb:25 +msgid "outgoing message" +msgstr "" + +#: locale/model_attributes.rb:50 +msgid "post redirect" +msgstr "" + +#: locale/model_attributes.rb:14 +msgid "profile photo" +msgstr "" + +#: locale/model_attributes.rb:2 +msgid "public body" +msgstr "" + +#: locale/model_attributes.rb:47 +msgid "raw email" +msgstr "" + +#: locale/model_attributes.rb:31 +msgid "track thing" +msgstr "" + +#: locale/model_attributes.rb:69 +msgid "user" +msgstr "" + +#: locale/model_attributes.rb:67 +msgid "user info request sent alert" +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..1615b5f7e --- /dev/null +++ b/locale/es/app.po @@ -0,0 +1,877 @@ +# 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-31 08:59+0100\n" +"PO-Revision-Date: 2011-03-31 09:27+0100\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" +"Language: \n" +"Plural-Forms: nplurals=2; plural=n>1;" + +#: app/views/public_body/show.rhtml:81 +msgid "%d Freedom of Information request" +msgid_plural "%d Freedom of Information requests" +msgstr[0] "%d Libera de Information requesto" +msgstr[1] "Libera de Information requesti numbera %d" + +#: app/views/general/frontpage.rhtml:36 +msgid "%d request" +msgid_plural "%d requests" +msgstr[0] "%d nonna requesti" +msgstr[1] "%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 "<a href=\"%s\">Browso tutto</a> ou <a href=\"%s\">demandus adder une</a>." + +#: app/views/public_body/show.rhtml:50 +msgid "" +"<a href=\"%s\">Make a new Freedom of Information request</a> to " +"{{public_body_name}}" +msgstr "<a href=\"%s\">Makando une Libera de Information requesti</a> a {{public_body_name}}" + +#: 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 "" +"<strong><code>commented_by:tony_bowden</code></strong> a busquar annotationi \n" +"makando para Tony Bowden, typar la nom con en el URL." + +#: 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 "" +"No busquara? <a href=\"%s\">Browse tutti</a> ou <a href=\"%s\">demanda a nous a addare \"\n" +"\"la</a> " + +#: locale/model_attributes.rb:46 +msgid "CensorRule|Last edit comment" +msgstr "" + +#: locale/model_attributes.rb:45 +msgid "CensorRule|Last edit editor" +msgstr "" + +#: locale/model_attributes.rb:44 +msgid "CensorRule|Replacement" +msgstr "" + +#: locale/model_attributes.rb:43 +msgid "CensorRule|Text" +msgstr "" + +#: app/views/public_body/show.rhtml:17 app/views/public_body/show.rhtml:19 +msgid "Charity registration" +msgstr "" + +#: locale/model_attributes.rb:22 +msgid "Comment|Body" +msgstr "" + +#: locale/model_attributes.rb:21 +msgid "Comment|Comment type" +msgstr "" + +#: locale/model_attributes.rb:24 +msgid "Comment|Locale" +msgstr "" + +#: locale/model_attributes.rb:23 +msgid "Comment|Visible" +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 "" + +#: locale/model_attributes.rb:61 +msgid "EximLogDone|Filename" +msgstr "" + +#: locale/model_attributes.rb:62 +msgid "EximLogDone|Last stat" +msgstr "" + +#: locale/model_attributes.rb:19 +msgid "EximLog|Line" +msgstr "" + +#: locale/model_attributes.rb:18 +msgid "EximLog|Order" +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> \n" +"tu <br>amo informatia. <strong>Con legalando, se obligandus respondre</strong> (<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 +msgid "Freedom of Information requests made" +msgstr "Makando Libera de Information requesti" + +#: app/views/public_body/show.rhtml:73 +msgid "Freedom of Information requests made using this site" +msgstr "Makando Libera de Information requesti con la site isto" + +#: app/views/layouts/default.rhtml:123 +msgid "Hello!" +msgstr "Nomjour!" + +#: app/views/layouts/default.rhtml:120 +msgid "Hello, {{username}}!" +msgstr "¡{{username}} hola!" + +#: app/views/layouts/default.rhtml:115 +msgid "Help" +msgstr "Aider" + +#: locale/model_attributes.rb:58 +msgid "Holiday|Day" +msgstr "" + +#: locale/model_attributes.rb:59 +msgid "Holiday|Description" +msgstr "" + +#: app/views/public_body/show.rhtml:8 +msgid "Home page of authority" +msgstr "La pago home del authoritias" + +#: locale/model_attributes.rb:64 +msgid "IncomingMessage|Cached attachment text clipped" +msgstr "" + +#: locale/model_attributes.rb:65 +msgid "IncomingMessage|Cached main body text folded" +msgstr "" + +#: locale/model_attributes.rb:66 +msgid "IncomingMessage|Cached main body text unfolded" +msgstr "" + +#: locale/model_attributes.rb:39 +msgid "InfoRequestEvent|Calculated state" +msgstr "" + +#: locale/model_attributes.rb:38 +msgid "InfoRequestEvent|Described state" +msgstr "" + +#: locale/model_attributes.rb:36 +msgid "InfoRequestEvent|Event type" +msgstr "" + +#: locale/model_attributes.rb:40 +msgid "InfoRequestEvent|Last described at" +msgstr "" + +#: locale/model_attributes.rb:37 +msgid "InfoRequestEvent|Params yaml" +msgstr "" + +#: locale/model_attributes.rb:41 +msgid "InfoRequestEvent|Prominence" +msgstr "" + +#: locale/model_attributes.rb:87 +msgid "InfoRequest|Allow new responses from" +msgstr "" + +#: locale/model_attributes.rb:83 +msgid "InfoRequest|Awaiting description" +msgstr "" + +#: locale/model_attributes.rb:82 +msgid "InfoRequest|Described state" +msgstr "" + +#: locale/model_attributes.rb:88 +msgid "InfoRequest|Handle rejected responses" +msgstr "" + +#: locale/model_attributes.rb:86 +msgid "InfoRequest|Law used" +msgstr "" + +#: locale/model_attributes.rb:84 +msgid "InfoRequest|Prominence" +msgstr "" + +#: locale/model_attributes.rb:81 +msgid "InfoRequest|Title" +msgstr "" + +#: locale/model_attributes.rb:85 +msgid "InfoRequest|Url title" +msgstr "" + +#: app/views/layouts/default.rhtml:17 +msgid "Make and browse Freedom of Information (FOI) requests" +msgstr "Makando et browser los Libera de Information requesti" + +#: app/views/layouts/default.rhtml:89 +msgid "Make and explore Freedom of Information requests" +msgstr "Makando et explorator los Libera de Information requesti" + +#: app/views/general/frontpage.rhtml:4 +msgid "Make or explore Freedom of Information requests" +msgstr "\"Makando ou explorator los Libera de Information requesti" + +#: app/views/layouts/default.rhtml:108 +msgid "Make request" +msgstr "Creer requesto" + +#: app/views/public_body/show.rhtml:6 +msgid "More about this authority" +msgstr "Mas ou subjet du autoritas" + +#: app/views/general/frontpage.rhtml:41 +msgid "More authorities..." +msgstr "Mas autorititatas..." + +#: app/views/general/frontpage.rhtml:55 +msgid "More successful requests..." +msgstr "Mas requestos de suces" + +#: app/views/layouts/default.rhtml:112 +msgid "My requests" +msgstr "Mes requestos" + +#: app/models/public_body.rb:36 +msgid "Name can't be blank" +msgstr "Nom ne possiblo emptar" + +#: app/models/public_body.rb:40 +msgid "Name is already taken" +msgstr "Nom deja prendar" + +#: app/views/general/search.rhtml:40 +msgid "Newest results first" +msgstr "Los resultas la mas nouvela premer" + +#: app/views/general/search.rhtml:16 +msgid "Next, select the public authority you'd like to make the request from." +msgstr "Maintena, shala el authoritas publicas que tu aimer requestar por" + +#: app/views/general/search.rhtml:48 +msgid "No public authorities found" +msgstr "Nulla authoritas publiqua trouves" + +#: 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 "Nonna persona crear los requestos Libras Informatias a {{public_body_name}} con esto sita" + +#: app/views/general/search.rhtml:7 +msgid "Nothing found for '{{search_terms}}'" +msgstr "Rien por {{search_terms}}" + +#: app/views/general/frontpage.rhtml:25 +msgid "" +"OR, <strong>search</strong> for information others have requested using " +"{{site_name}}" +msgstr "Ou <strong>busqar</strong> per infos los autros requesta com {{site_name}}" + +#: app/views/public_body/show.rhtml:92 +msgid "Only requests made using {{site_name}} are shown." +msgstr "Seul los requestos crear con {{site_name}} heerro" + +#: locale/model_attributes.rb:26 +msgid "OutgoingMessage|Body" +msgstr "" + +#: locale/model_attributes.rb:29 +msgid "OutgoingMessage|Last sent at" +msgstr "" + +#: locale/model_attributes.rb:28 +msgid "OutgoingMessage|Message type" +msgstr "" + +#: locale/model_attributes.rb:27 +msgid "OutgoingMessage|Status" +msgstr "" + +#: locale/model_attributes.rb:30 +msgid "OutgoingMessage|What doing" +msgstr "" + +#: app/views/general/search.rhtml:80 +msgid "" +"People {{start_count}} to {{end_count}} of {{total_count}} for " +"{{user_search_query}}" +msgstr "Peuples {{start_count}} a {{end_count}} de {{total_count}} pour {{user_search_query}}" + +#: 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 "Por favor, show el typo de respondra tu creeara" + +#: 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 "Por favor, creear una suject" + +#: 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 "" + +#: locale/model_attributes.rb:56 +msgid "PostRedirect|Circumstance" +msgstr "" + +#: locale/model_attributes.rb:54 +msgid "PostRedirect|Email token" +msgstr "" + +#: locale/model_attributes.rb:53 +msgid "PostRedirect|Post params yaml" +msgstr "" + +#: locale/model_attributes.rb:55 +msgid "PostRedirect|Reason params yaml" +msgstr "" + +#: locale/model_attributes.rb:51 +msgid "PostRedirect|Token" +msgstr "" + +#: locale/model_attributes.rb:52 +msgid "PostRedirect|Uri" +msgstr "" + +#: locale/model_attributes.rb:15 +msgid "ProfilePhoto|Data" +msgstr "" + +#: locale/model_attributes.rb:16 +msgid "ProfilePhoto|Draft" +msgstr "" + +#: app/views/general/search.rhtml:70 +msgid "" +"Public authorities {{start_count}} to {{end_count}} of {{total_count}} for " +"{{user_search_query}}" +msgstr "" + +#: locale/model_attributes.rb:12 +msgid "PublicBody|First letter" +msgstr "El premier lettre" + +#: locale/model_attributes.rb:10 +msgid "PublicBody|Home page" +msgstr "La page de home" + +#: locale/model_attributes.rb:8 +msgid "PublicBody|Last edit comment" +msgstr "" + +#: locale/model_attributes.rb:7 +msgid "PublicBody|Last edit editor" +msgstr "" + +#: locale/model_attributes.rb:3 +msgid "PublicBody|Name" +msgstr "La Nom" + +#: locale/model_attributes.rb:11 +msgid "PublicBody|Notes" +msgstr "" + +#: locale/model_attributes.rb:13 +msgid "PublicBody|Publication scheme" +msgstr "" + +#: locale/model_attributes.rb:5 +msgid "PublicBody|Request email" +msgstr "" + +#: locale/model_attributes.rb:4 +msgid "PublicBody|Short name" +msgstr "La nom breva" + +#: locale/model_attributes.rb:9 +msgid "PublicBody|Url name" +msgstr "" + +#: locale/model_attributes.rb:6 +msgid "PublicBody|Version" +msgstr "" + +#: app/views/public_body/show.rhtml:11 +msgid "Publication scheme" +msgstr "" + +#: locale/model_attributes.rb:49 +msgid "RawEmail|Data binary" +msgstr "" + +#: locale/model_attributes.rb:48 +msgid "RawEmail|Data text" +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 "Lire bloggo" + +#: app/views/general/search.rhtml:42 +msgid "Recently described results first" +msgstr "Los resultas recentas decriba au premier" + +#: app/views/general/search.rhtml:9 +msgid "Results page {{page_number}}" +msgstr "Page de resultas numero {{page_number}}" + +#: 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 +msgid "Search Freedom of Information requests, public authorities and users" +msgstr "Busquare Libra Info Requesta, authoritas et personna" + +#: 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 "Enregister au signin" + +#: app/views/layouts/default.rhtml:121 +msgid "Sign out" +msgstr "Exito" + +#: 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 "Traqo esto authotito" + +#: locale/model_attributes.rb:33 +msgid "TrackThing|Track medium" +msgstr "" + +#: locale/model_attributes.rb:32 +msgid "TrackThing|Track query" +msgstr "" + +#: locale/model_attributes.rb:34 +msgid "TrackThing|Track type" +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 "" + +#: locale/model_attributes.rb:68 +msgid "UserInfoRequestSentAlert|Alert type" +msgstr "" + +#: locale/model_attributes.rb:79 +msgid "User|About me" +msgstr "" + +#: locale/model_attributes.rb:77 +msgid "User|Admin level" +msgstr "" + +#: locale/model_attributes.rb:78 +msgid "User|Ban text" +msgstr "" + +#: locale/model_attributes.rb:70 +msgid "User|Email" +msgstr "" + +#: locale/model_attributes.rb:74 +msgid "User|Email confirmed" +msgstr "" + +#: locale/model_attributes.rb:72 +msgid "User|Hashed password" +msgstr "" + +#: locale/model_attributes.rb:76 +msgid "User|Last daily track email" +msgstr "" + +#: locale/model_attributes.rb:71 +msgid "User|Name" +msgstr "" + +#: locale/model_attributes.rb:73 +msgid "User|Salt" +msgstr "" + +#: locale/model_attributes.rb:75 +msgid "User|Url name" +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 "en additionado, nomme {{public_body_short_name}}" + +#: locale/model_attributes.rb:42 +msgid "censor rule" +msgstr "" + +#: locale/model_attributes.rb:20 +msgid "comment" +msgstr "" + +#: app/views/general/frontpage.rhtml:18 +msgid "e.g." +msgstr "par exemplo" + +#: locale/model_attributes.rb:17 +msgid "exim log" +msgstr "" + +#: locale/model_attributes.rb:60 +msgid "exim log done" +msgstr "" + +#: locale/model_attributes.rb:57 +msgid "holiday" +msgstr "" + +#: locale/model_attributes.rb:63 +msgid "incoming message" +msgstr "" + +#: locale/model_attributes.rb:80 +msgid "info request" +msgstr "" + +#: locale/model_attributes.rb:35 +msgid "info request event" +msgstr "" + +#: locale/model_attributes.rb:25 +msgid "outgoing message" +msgstr "" + +#: locale/model_attributes.rb:50 +msgid "post redirect" +msgstr "" + +#: locale/model_attributes.rb:14 +msgid "profile photo" +msgstr "" + +#: locale/model_attributes.rb:2 +msgid "public body" +msgstr "" + +#: locale/model_attributes.rb:47 +msgid "raw email" +msgstr "" + +#: locale/model_attributes.rb:31 +msgid "track thing" +msgstr "" + +#: locale/model_attributes.rb:69 +msgid "user" +msgstr "" + +#: locale/model_attributes.rb:67 +msgid "user info request sent alert" +msgstr "" + +#: app/views/general/frontpage.rhtml:51 +msgid "{{length_of_time}} ago" +msgstr "depuis {{length_of_time}}" + +#~ msgid "activerecord.errors.full_messages.format" +#~ msgstr "%{message}" diff --git a/public/images/navimg/alaveteli-logo-header.png b/public/images/navimg/alaveteli-logo-header.png Binary files differnew file mode 100644 index 000000000..49b529718 --- /dev/null +++ b/public/images/navimg/alaveteli-logo-header.png diff --git a/public/images/navimg/alaveteli-logo.png b/public/images/navimg/alaveteli-logo.png Binary files differnew file mode 100644 index 000000000..ce9abdd3d --- /dev/null +++ b/public/images/navimg/alaveteli-logo.png 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..fc693f6c8 --- /dev/null +++ b/script/generate_pot.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +cd `dirname $0` + +rake gettext:store_model_attributes +rake gettext:find + +#rake translate_routes:update_yaml["en es"] diff --git a/spec/controllers/admin_public_body_controller_spec.rb b/spec/controllers/admin_public_body_controller_spec.rb index db2e449f8..a32c27dd9 100644 --- a/spec/controllers/admin_public_body_controller_spec.rb +++ b/spec/controllers/admin_public_body_controller_spec.rb @@ -2,7 +2,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe AdminPublicBodyController, "when administering public bodies" do integrate_views - fixtures :public_bodies + fixtures :public_bodies, :public_body_translations it "shows the index page" do get :index @@ -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/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb index 648a66e28..b4b989c9f 100644 --- a/spec/controllers/request_controller_spec.rb +++ b/spec/controllers/request_controller_spec.rb @@ -1,3 +1,7 @@ +# £2k p/a +# talk about margins +# + require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') require 'json' @@ -34,7 +38,7 @@ end describe RequestController, "when showing one request" do - fixtures :info_requests, :info_request_events, :public_bodies, :users, :incoming_messages, :raw_emails, :outgoing_messages, :comments # all needed as integrating views + fixtures :info_requests, :info_request_events, :public_bodies, :public_body_translations, :users, :incoming_messages, :raw_emails, :outgoing_messages, :comments # all needed as integrating views it "should be successful" do get :show, :url_title => 'why_do_you_have_such_a_fancy_dog' diff --git a/spec/controllers/track_controller_spec.rb b/spec/controllers/track_controller_spec.rb index c31491375..9fe3ebd42 100644 --- a/spec/controllers/track_controller_spec.rb +++ b/spec/controllers/track_controller_spec.rb @@ -35,13 +35,13 @@ end 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 + fixtures :info_requests, :outgoing_messages, :incoming_messages, :raw_emails, :info_request_events, :users, :track_things, :track_things_sent_emails, :public_bodies, :public_body_translations 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) @@ -94,7 +94,7 @@ end describe TrackController, "when viewing RSS feed for a track" do integrate_views - fixtures :info_requests, :outgoing_messages, :incoming_messages, :raw_emails, :info_request_events, :users, :track_things, :comments, :public_bodies + fixtures :info_requests, :outgoing_messages, :incoming_messages, :raw_emails, :info_request_events, :users, :track_things, :comments, :public_bodies, :public_body_translations before do rebuild_xapian_index 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 @@ -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/gems/fast_gettext-0.5.10/lib/fast_gettext/storage.rb b/vendor/gems/fast_gettext-0.5.10/lib/fast_gettext/storage.rb index 7c65fd57a..3ad4ed5b8 100644 --- a/vendor/gems/fast_gettext-0.5.10/lib/fast_gettext/storage.rb +++ b/vendor/gems/fast_gettext-0.5.10/lib/fast_gettext/storage.rb @@ -189,4 +189,4 @@ module FastGettext self.current_cache = caches[text_domain][locale] end end -end
\ No newline at end of file +end 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..d8f0adaa3 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?(Array) + values = values.flatten + value = values.reject{|x| x.nil?} + else + values = values.reject{|x| x.nil?} + value = values.join(" ") + 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/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/gettext_i18n_rails/lib/gettext_i18n_rails/tasks.rb b/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/tasks.rb index b52157a2f..39fa4d959 100644 --- a/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/tasks.rb +++ b/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/tasks.rb @@ -61,7 +61,7 @@ namespace :gettext do # require 'gettext_activerecord/parser' desc "write the model attributes to <locale_path>/model_attributes.rb" task :store_model_attributes => :environment do - FastGettext.silence_errors + #FastGettext.silence_errors require 'gettext_i18n_rails/model_attributes_finder' require 'gettext_i18n_rails/active_record' 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 |