From d7fee6b905378a4d92b4c9da99b180003920b470 Mon Sep 17 00:00:00 2001 From: Caio SBA Date: Thu, 9 Dec 2010 03:38:22 -0200 Subject: [PATCH] Adding articles translation support --- app/controllers/my_profile/cms_controller.rb | 9 +++++++++ app/controllers/public/content_viewer_controller.rb | 26 ++++++++++++++++++++++++++ app/helpers/application_helper.rb | 2 +- app/helpers/content_viewer_helper.rb | 12 ++++++++++++ app/models/article.rb | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ app/models/blog.rb | 4 ++++ app/models/blog_archives_block.rb | 2 +- app/models/environment.rb | 2 +- app/models/event.rb | 4 ++++ app/models/rss_feed.rb | 3 ++- app/models/textile_article.rb | 4 ++++ app/models/tiny_mce_article.rb | 4 ++++ app/views/cms/_blog.rhtml | 3 +++ app/views/cms/_event.rhtml | 2 ++ app/views/cms/_textile_article.rhtml | 2 ++ app/views/cms/_tiny_mce_article.rhtml | 2 ++ app/views/cms/_translatable.rhtml | 7 +++++++ app/views/content_viewer/view_page.rhtml | 6 ++++++ db/migrate/20101205034144_add_language_and_translation_of_id_to_article.rb | 29 +++++++++++++++++++++++++++++ features/edit_article.feature | 29 +++++++++++++++++++++++++++++ public/designs/icons/tango/style.css | 1 + public/stylesheets/application.css | 43 +++++++++++++++++++++++++++++++++++++++++++ test/functional/application_controller_test.rb | 22 ++++++++++++++++++++++ test/functional/cms_controller_test.rb | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/functional/content_viewer_controller_test.rb | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/unit/article_test.rb | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/unit/blog_archives_block_test.rb | 32 ++++++++++++++++++++++++++++++++ test/unit/blog_test.rb | 16 ++++++++++++++++ test/unit/event_test.rb | 6 ++++++ test/unit/rss_feed_test.rb | 20 ++++++++++++++++++++ test/unit/textile_article_test.rb | 5 +++++ test/unit/tiny_mce_article_test.rb | 5 ++++- 32 files changed, 736 insertions(+), 5 deletions(-) create mode 100644 app/views/cms/_translatable.rhtml create mode 100644 db/migrate/20101205034144_add_language_and_translation_of_id_to_article.rb diff --git a/app/controllers/my_profile/cms_controller.rb b/app/controllers/my_profile/cms_controller.rb index cb0394d..8b9af2b 100644 --- a/app/controllers/my_profile/cms_controller.rb +++ b/app/controllers/my_profile/cms_controller.rb @@ -89,6 +89,7 @@ class CmsController < MyProfileController @article = profile.articles.find(params[:id]) @parent_id = params[:parent_id] @type = params[:type] || @article.class.to_s + translations if @article.translatable? continue = params[:continue] refuse_blocks @@ -138,6 +139,8 @@ class CmsController < MyProfileController @parent_id = parent.id end + translations if @article.translatable? + @article.profile = profile @article.last_changed_by = user @@ -367,5 +370,11 @@ class CmsController < MyProfileController def per_page 10 end + + def translations + @locales = Noosfero.locales.invert.reject { |name, lang| !@article.possible_translations.include?(lang) } + @selected_locale = @article.language || FastGettext.locale + end + end diff --git a/app/controllers/public/content_viewer_controller.rb b/app/controllers/public/content_viewer_controller.rb index 56d93da..7c74a12 100644 --- a/app/controllers/public/content_viewer_controller.rb +++ b/app/controllers/public/content_viewer_controller.rb @@ -51,6 +51,8 @@ class ContentViewerController < ApplicationController return end + redirect_to_translation + # At this point the page will be showed @page.hit @@ -85,7 +87,11 @@ class ContentViewerController < ApplicationController @page.posts end + posts = posts.native_translations if @page.blog? && @page.display_posts_in_current_language? + @posts = posts.paginate({ :page => params[:npage], :per_page => @page.posts_per_page }.merge(Article.display_filter(user, profile))) + + @posts.map!{ |p| p.get_translation_to(FastGettext.locale) } if @page.blog? && @page.display_posts_in_current_language? end if @page.folder? && @page.gallery? @@ -125,4 +131,24 @@ class ContentViewerController < ApplicationController def per_page 12 end + + def redirect_to_translation + locale = FastGettext.locale + if !@page.language.nil? && @page.language != locale + translations = [@page.native_translation] + @page.native_translation.translations + urls = translations.map{ |t| URI.parse(url_for(t.url)).path } + urls << URI.parse(url_for(profile.admin_url.merge({ :controller => 'cms', :action => 'edit', :id => @page.id }))).path + urls << URI.parse(url_for(profile.admin_url.merge(:controller => 'cms', :action => 'new'))).path + referer = URI.parse(url_for(request.referer)).path unless request.referer.blank? + unless urls.include?(referer) + translations.each do |translation| + if translation.language == locale + @page = translation + redirect_to :profile => @page.profile.identifier, :page => @page.explode_path + end + end + end + end + end + end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 3e3cea9..72f22e4 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -27,7 +27,7 @@ module ApplicationHelper include AccountHelper def locale - FastGettext.locale + (@page && !@page.language.blank?) ? @page.language : FastGettext.locale end def load_web2_conf diff --git a/app/helpers/content_viewer_helper.rb b/app/helpers/content_viewer_helper.rb index a835779..b43b76d 100644 --- a/app/helpers/content_viewer_helper.rb +++ b/app/helpers/content_viewer_helper.rb @@ -35,4 +35,16 @@ module ContentViewerHelper text && (text.first(40) + (text.size > 40 ? '…' : '')) end + def article_translations(article) + unless article.native_translation.translations.empty? + links = (article.native_translation.translations + [article.native_translation]).map do |translation| + { Noosfero.locales[translation.language] => { :href => url_for(translation.url) } } + end + content_tag(:div, link_to(_('Translations'), '#', + :onclick => "toggleSubmenu(this, '#{_('Translations')}', #{links.to_json}); return false", + :class => 'article-translations-menu simplemenu-trigger up'), + :class => 'article-translations') + end + end + end diff --git a/app/models/article.rb b/app/models/article.rb index c43a721..c6bc062 100644 --- a/app/models/article.rb +++ b/app/models/article.rb @@ -28,6 +28,10 @@ class Article < ActiveRecord::Base belongs_to :reference_article, :class_name => "Article", :foreign_key => 'reference_article_id' + has_many :translations, :class_name => 'Article', :foreign_key => :translation_of_id + belongs_to :translation_of, :class_name => 'Article', :foreign_key => :translation_of_id + before_destroy :rotate_translations + before_create do |article| article.published_at = article.created_at if article.published_at.nil? if article.reference_article && !article.parent @@ -53,6 +57,10 @@ class Article < ActiveRecord::Base URL_FORMAT = /\A(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?\Z/ix validates_format_of :external_link, :with => URL_FORMAT, :if => lambda { |article| !article.external_link.blank? } + validate :known_language + validate :used_translation + validate :native_translation_must_have_language + validate :translation_must_have_language def is_trackable? self.published? && self.notifiable? && self.advertise? @@ -251,6 +259,65 @@ class Article < ActiveRecord::Base false end + named_scope :native_translations, :conditions => { :translation_of_id => nil } + + def translatable? + false + end + + def native_translation + self.translation_of.nil? ? self : self.translation_of + end + + def possible_translations + possibilities = Noosfero.locales.keys - self.native_translation.translations(:select => :language).map(&:language) - [self.native_translation.language] + possibilities << self.language unless self.language_changed? + possibilities + end + + def known_language + unless self.language.blank? + errors.add(:language, N_('Language not supported by Noosfero')) unless Noosfero.locales.key?(self.language) + end + end + + def used_translation + unless self.language.blank? or self.translation_of.nil? + errors.add(:language, N_('Language is already used')) unless self.possible_translations.include?(self.language) + end + end + + def translation_must_have_language + unless self.translation_of.nil? + errors.add(:language, N_('Language must be choosen')) if self.language.blank? + end + end + + def native_translation_must_have_language + unless self.translation_of.nil? + errors.add_to_base(N_('A language must be choosen for the native article')) if self.translation_of.language.blank? + end + end + + def rotate_translations + unless self.translations.empty? + rotate = self.translations + root = rotate.shift + root.update_attribute(:translation_of_id, nil) + root.translations = rotate + end + end + + def get_translation_to(locale) + if self.language.nil? || self.language == locale + self + elsif self.native_translation.language == locale + self.native_translation + else + self.native_translation.translations.first(:conditions => { :language => locale }) || self + end + end + def published? if self.published if self.parent && !self.parent.published? diff --git a/app/models/blog.rb b/app/models/blog.rb index 55d838d..3fd7950 100644 --- a/app/models/blog.rb +++ b/app/models/blog.rb @@ -57,4 +57,8 @@ class Blog < Folder settings_items :visualization_format, :type => :string, :default => 'full' validates_inclusion_of :visualization_format, :in => [ 'full', 'short' ], :if => :visualization_format + settings_items :display_posts_in_current_language, :type => :boolean, :default => true + + alias :display_posts_in_current_language? :display_posts_in_current_language + end diff --git a/app/models/blog_archives_block.rb b/app/models/blog_archives_block.rb index e6b8284..6d370b9 100644 --- a/app/models/blog_archives_block.rb +++ b/app/models/blog_archives_block.rb @@ -24,7 +24,7 @@ class BlogArchivesBlock < Block owner_blog = self.blog return nil unless owner_blog results = '' - owner_blog.posts.group_by {|i| i.published_at.year }.sort_by { |year,count| -year }.each do |year, results_by_year| + owner_blog.posts.native_translations.group_by {|i| i.published_at.year }.sort_by { |year,count| -year }.each do |year, results_by_year| results << content_tag('li', content_tag('strong', "#{year} (#{results_by_year.size})")) results << "