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 << "
"
results_by_year.group_by{|i| [ ('%02d' % i.published_at.month()), gettext(MONTHS[i.published_at.month() - 1])]}.sort.reverse.each do |month, results_by_month|
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 6cee1d2..34cc7fe 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -108,7 +108,7 @@ class Environment < ActiveRecord::Base
'admin_must_approve_new_communities' => _("Admin must approve creation of communities"),
'enterprises_are_disabled_when_created' => __('Enterprises are disabled when created'),
'show_balloon_with_profile_links_when_clicked' => _('Show a balloon with profile links when a profile image is clicked'),
- 'xmpp_chat' => _('XMPP/Jabber based chat'),
+ 'xmpp_chat' => _('XMPP/Jabber based chat')
}
end
diff --git a/app/models/event.rb b/app/models/event.rb
index 6f103c0..5746dbb 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -120,6 +120,10 @@ class Event < Article
true
end
+ def translatable?
+ true
+ end
+
include MaybeAddHttp
end
diff --git a/app/models/rss_feed.rb b/app/models/rss_feed.rb
index d848428..6cad49d 100644
--- a/app/models/rss_feed.rb
+++ b/app/models/rss_feed.rb
@@ -62,7 +62,8 @@ class RssFeed < Article
include ActionController::UrlWriter
def fetch_articles
if parent && parent.has_posts?
- return parent.posts.find(:all, :conditions => ['published = ?', true], :limit => self.limit, :order => 'id desc')
+ language = self.language.blank? ? {} : { :language => self.language }
+ return parent.posts.find(:all, :conditions => { :published => true }.merge(language), :limit => self.limit, :order => 'id desc')
end
articles =
diff --git a/app/models/textile_article.rb b/app/models/textile_article.rb
index 8bf2c4d..ea25554 100644
--- a/app/models/textile_article.rb
+++ b/app/models/textile_article.rb
@@ -16,4 +16,8 @@ class TextileArticle < TextArticle
true
end
+ def translatable?
+ true
+ end
+
end
diff --git a/app/models/tiny_mce_article.rb b/app/models/tiny_mce_article.rb
index 3788945..160587f 100644
--- a/app/models/tiny_mce_article.rb
+++ b/app/models/tiny_mce_article.rb
@@ -19,4 +19,8 @@ class TinyMceArticle < TextArticle
true
end
+ def translatable?
+ true
+ end
+
end
diff --git a/app/views/cms/_blog.rhtml b/app/views/cms/_blog.rhtml
index 7db52f2..b3304d2 100644
--- a/app/views/cms/_blog.rhtml
+++ b/app/views/cms/_blog.rhtml
@@ -56,8 +56,11 @@
<%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, [5, 10, 20, 50, 100])) %>
+<%= labelled_check_box(_('Display posts in current language, if available'), 'article[display_posts_in_current_language]', '1', @article.display_posts_in_current_language?) %>
+
<% f.fields_for 'feed', @article.feed do |feed| %>
<%= labelled_form_field(_('Limit of posts in RSS Feed'), feed.select(:limit, [5, 10, 20, 50])) %>
+ <%= labelled_form_field(_('Include in RSS Feed only posts from language:'), feed.select(:language, { _('All') => nil }.merge(Noosfero.locales.invert))) %>
<% end %>
<% f.fields_for 'external_feed_builder', @article.external_feed do |efeed| %>
diff --git a/app/views/cms/_event.rhtml b/app/views/cms/_event.rhtml
index 881ade3..f5fd5a6 100644
--- a/app/views/cms/_event.rhtml
+++ b/app/views/cms/_event.rhtml
@@ -5,6 +5,8 @@
<%= required f.text_field('name', :size => '64') %>
+<%= render :partial => 'translatable' %>
+
<%= labelled_form_field(_('Start date'), pick_date(:article, :start_date)) %>
<%= labelled_form_field(_('End date'), pick_date(:article, :end_date)) %>
diff --git a/app/views/cms/_textile_article.rhtml b/app/views/cms/_textile_article.rhtml
index 9cf0413..b9d0eab 100644
--- a/app/views/cms/_textile_article.rhtml
+++ b/app/views/cms/_textile_article.rhtml
@@ -4,6 +4,8 @@
<%= required labelled_form_field(_('Title'), text_field(:article, 'name', :size => '64')) %>
+<%= render :partial => 'translatable' %>
+
<%= button :add, _("Lead"), '#', :id => "lead-button", :style => "margin-left: 0px;" %>
<%= _('Used when a short version of your text is needed.') %>
diff --git a/app/views/cms/_tiny_mce_article.rhtml b/app/views/cms/_tiny_mce_article.rhtml
index d2d3c1e..7224993 100644
--- a/app/views/cms/_tiny_mce_article.rhtml
+++ b/app/views/cms/_tiny_mce_article.rhtml
@@ -11,6 +11,8 @@
<%= required labelled_form_field(_('Title'), text_field(:article, 'name', :size => '64')) %>
<% end %>
+ <%= render :partial => 'translatable' %>
+
<%= button :add, _("Lead"), '#', :id => "lead-button", :style => "margin-left: 0px;" %>
<%= _('Used when a short version of your text is needed.') %>
diff --git a/app/views/cms/_translatable.rhtml b/app/views/cms/_translatable.rhtml
new file mode 100644
index 0000000..4f69bed
--- /dev/null
+++ b/app/views/cms/_translatable.rhtml
@@ -0,0 +1,7 @@
+<% if @article.translatable? %>
+
+ <%= label :article, :language, _('Language') %>
+ <%= select :article, :language, @locales, { :selected => @selected_locale, :include_blank => true } %>
+ <%= hidden_field(:article, :translation_of_id) %>
+
+<% end %>
diff --git a/app/views/content_viewer/view_page.rhtml b/app/views/content_viewer/view_page.rhtml
index 5e4bada..e7b969f 100644
--- a/app/views/content_viewer/view_page.rhtml
+++ b/app/views/content_viewer/view_page.rhtml
@@ -35,6 +35,11 @@
<% end %>
<% if !(profile.kind_of?(Enterprise) && environment.enabled?('disable_cms')) %>
<% if !@page.gallery? %>
+ <%= link_to _('Add translation'),
+ profile.admin_url.merge(:controller => 'cms', :action => 'new',
+ :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)),
+ :type => @page.type, :article => { :translation_of_id => @page.native_translation.id }),
+ :class => 'button with-text icon-locale' if @page.translatable? && !@page.native_translation.language.blank? %>
<%= lightbox_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) %>
<% end %>
<% if (@page.folder? && !@page.has_posts?) || (@page.parent && @page.parent.folder? && !@page.parent.has_posts?) %>
@@ -50,6 +55,7 @@
<%= link_to content_tag( 'span', _('Suggest an article') ), profile.admin_url.merge({ :controller => 'cms', :action => 'suggest_an_article'}), :class => 'button with-text icon-new' %>
<% end %>
<% end %>
+ <%= article_translations(@page) %>
<%= link_to(image_tag('icons-mime/rss-feed.png'), @page.feed.url, :class => 'blog-feed-link') if @page.has_posts? && @page.feed %>
<%= article_title(@page, :no_link => true) %>
diff --git a/db/migrate/20101205034144_add_language_and_translation_of_id_to_article.rb b/db/migrate/20101205034144_add_language_and_translation_of_id_to_article.rb
new file mode 100644
index 0000000..3db0d88
--- /dev/null
+++ b/db/migrate/20101205034144_add_language_and_translation_of_id_to_article.rb
@@ -0,0 +1,29 @@
+class AddLanguageAndTranslationOfIdToArticle < ActiveRecord::Migration
+ def self.up
+ add_column :articles, :translation_of_id, :interger
+ add_column :articles, :language, :string
+
+ add_column :article_versions, :translation_of_id, :interger
+ add_column :article_versions, :language, :string
+
+ add_index :articles, :translation_of_id
+
+ select_all("select id, setting from articles where type = 'Blog'").each do |blog|
+ settings = YAML.load(blog['setting'])
+ settings[:display_posts_in_current_language] = true
+ assignments = ActiveRecord::Base.sanitize_sql_for_assignment(:setting => settings.to_yaml)
+ update("update articles set %s where id = %d" % [assignments, blog['id']])
+ end
+
+ end
+
+ def self.down
+ remove_index :articles, :translation_of_id
+
+ remove_column :article_versions, :translation_of_id
+ remove_column :article_versions, :language
+
+ remove_column :articles, :language
+ remove_column :articles, :translation_of_id
+ end
+end
diff --git a/features/edit_article.feature b/features/edit_article.feature
index a1bd43c..5c2463a 100644
--- a/features/edit_article.feature
+++ b/features/edit_article.feature
@@ -133,3 +133,32 @@ Feature: edit article
Then I should be on "My new article" edit page
And the "Title" field should contain "My new article"
And the "Text" field should contain "text for the new article"
+
+ Scenario: add a translation to an article
+ Given I am on Joao Silva's sitemap
+ And I follow "Save the whales"
+ Then I should not see "Add translation"
+ And I follow "Edit"
+ And I select "English" from "Language"
+ Then I press "Save"
+ And I follow "Add translation"
+ And I fill in "Title" with "Mi neuvo artículo"
+ And I select "Español" from "Language"
+ When I press "Save"
+ Then I should be on /joaosilva/save-the-whales
+ And I should see "Translations"
+
+ Scenario: not add a translation without a language
+ Given the following articles
+ | owner | name | language |
+ | joaosilva | Article in English | en |
+ And I am on Joao Silva's sitemap
+ And I follow "Article in English"
+ And I follow "Add translation"
+ And I fill in "Title" with "Article in Portuguese"
+ When I press "Save"
+ Then I should see "Language must be choosen"
+ And I select "Português" from "Language"
+ When I press "Save"
+ Then I should not see "Language must be choosen"
+ And I should be on /joaosilva/article-in-english
diff --git a/public/designs/icons/tango/style.css b/public/designs/icons/tango/style.css
index 5b7379f..bb88794 100644
--- a/public/designs/icons/tango/style.css
+++ b/public/designs/icons/tango/style.css
@@ -75,3 +75,4 @@
.icon-reply { background-image: url(Tango/16x16/actions/mail-reply-sender.png) }
.icon-newforum { background-image: url(Tango/16x16/apps/system-users.png) }
.icon-newgallery { background-image: url(Tango/16x16/mimetypes/image-x-generic.png) }
+.icon-locale { background-image: url(Tango/16x16/apps/preferences-desktop-locale.png) }
\ No newline at end of file
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
index bcba090..96b09db 100644
--- a/public/stylesheets/application.css
+++ b/public/stylesheets/application.css
@@ -5232,6 +5232,49 @@ h1#agenda-title {
margin-top: 10px;
}
+
+.article-translations-menu {
+ float: right;
+ bottom: -15px;
+}
+
+.opera .article-translations-menu {
+ bottom: -8px;
+}
+
+.webkit .article-translations-menu {
+ bottom: -10px;
+}
+
+.article-translations-menu {
+ text-decoration: none !important;
+ height: 0;
+}
+
+.article-translations .menu-submenu-header,
+.article-translations .menu-submenu-content,
+.article-translations .menu-submenu-footer {
+ background: none;
+}
+
+.article-translations .menu-submenu {
+ bottom: auto;
+ top: 60px;
+ right: 0;
+ border: 1px solid;
+ background: #fff;
+}
+
+.msie7 .article-translations .menu-submenu,
+.webkit .article-translations .menu-submenu,
+.opera .article-translations .menu-submenu {
+ top: 30px;
+}
+
+.article-translations .menu-submenu-list {
+ list-style: none;
+}
+
/* Forum */
.forum-posts .pagination {
diff --git a/test/functional/application_controller_test.rb b/test/functional/application_controller_test.rb
index 9fb3771..81af15d 100644
--- a/test/functional/application_controller_test.rb
+++ b/test/functional/application_controller_test.rb
@@ -419,4 +419,26 @@ class ApplicationControllerTest < Test::Unit::TestCase
assert_tag :tag => 'meta', :attributes => { :name => 'description', :content => assigns(:environment).name }
end
+ should 'set html lang as the article language if an article is present and has a language' do
+ a = fast_create(Article, :name => 'test article', :language => 'fr')
+ @controller.instance_variable_set('@page', a)
+ FastGettext.stubs(:locale).returns('es')
+ get :index
+ assert_tag :html, :attributes => { :lang => 'fr' }
+ end
+
+ should 'set html lang as locale if no page present' do
+ FastGettext.stubs(:locale).returns('es')
+ get :index
+ assert_tag :html, :attributes => { :lang => 'es' }
+ end
+
+ should 'set html lang as locale if page has no language' do
+ a = fast_create(Article, :name => 'test article', :language => nil)
+ @controller.instance_variable_set('@page', a)
+ FastGettext.stubs(:locale).returns('es')
+ get :index
+ assert_tag :html, :attributes => { :lang => 'es' }
+ end
+
end
diff --git a/test/functional/cms_controller_test.rb b/test/functional/cms_controller_test.rb
index a90b9db..2d0eaa7 100644
--- a/test/functional/cms_controller_test.rb
+++ b/test/functional/cms_controller_test.rb
@@ -1440,4 +1440,63 @@ class CmsControllerTest < Test::Unit::TestCase
assert_response :success
end
+ should 'article language should be selected' do
+ textile = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'textile', :language => 'ru')
+ get :edit, :profile => @profile.identifier, :id => textile.id
+ assert_tag :option, :attributes => { :selected => 'selected', :value => 'ru' }, :parent => {
+ :tag => 'select', :attributes => { :id => 'article_language'} }
+ end
+
+ should 'list possible languages and include blank option' do
+ get :new, :profile => @profile.identifier, :type => 'TextileArticle'
+ assert_equal Noosfero.locales.invert, assigns(:locales)
+ assert_tag :option, :attributes => { :value => '' }, :parent => {
+ :tag => 'select', :attributes => { :id => 'article_language'} }
+ end
+
+ should 'add translation to an article' do
+ textile = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'textile', :language => 'ru')
+ assert_difference Article, :count do
+ post :new, :profile => @profile.identifier, :type => 'TextileArticle', :article => { :name => 'english translation', :translation_of_id => textile.id, :language => 'en' }
+ end
+ end
+
+ should 'not display language selection if article is not translatable' do
+ blog = fast_create(Blog, :name => 'blog', :profile_id => @profile.id)
+ get :edit, :profile => @profile.identifier, :id => blog.id
+ assert_no_tag :select, :attributes => { :id => 'article_language'}
+ end
+
+ should 'display display posts in current language input checked on edit blog' do
+ get :new, :profile => profile.identifier, :type => 'Blog'
+ assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'article[display_posts_in_current_language]', :checked => 'checked' }
+ end
+
+ should 'update to false blog display posts in current language setting' do
+ profile.articles << Blog.new(:name => 'Blog for test', :profile => profile, :display_posts_in_current_language => true)
+ post :edit, :profile => profile.identifier, :id => profile.blog.id, :article => { :display_posts_in_current_language => false }
+ profile.blog.reload
+ assert !profile.blog.display_posts_in_current_language?
+ end
+
+ should 'update to true blog display posts in current language setting' do
+ profile.articles << Blog.new(:name => 'Blog for test', :profile => profile, :display_posts_in_current_language => false)
+ post :edit, :profile => profile.identifier, :id => profile.blog.id, :article => { :display_posts_in_current_language => true }
+ profile.blog.reload
+ assert profile.blog.display_posts_in_current_language?
+ end
+
+ should 'be checked display posts in current language checkbox' do
+ profile.articles << Blog.new(:name => 'Blog for test', :profile => profile, :display_posts_in_current_language => true)
+ get :edit, :profile => profile.identifier, :id => profile.blog.id
+ assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'article[display_posts_in_current_language]', :checked => 'checked' }
+ end
+
+ should 'be unchecked display posts in current language checkbox' do
+ profile.articles << Blog.new(:name => 'Blog for test', :profile => profile, :display_posts_in_current_language => false)
+ get :edit, :profile => profile.identifier, :id => profile.blog.id
+ assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'article[display_posts_in_current_language]' }
+ assert_no_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => 'article[display_posts_in_current_language]', :checked => 'checked' }
+ end
+
end
diff --git a/test/functional/content_viewer_controller_test.rb b/test/functional/content_viewer_controller_test.rb
index 36c0ef1..52e68a5 100644
--- a/test/functional/content_viewer_controller_test.rb
+++ b/test/functional/content_viewer_controller_test.rb
@@ -1095,4 +1095,147 @@ class ContentViewerControllerTest < Test::Unit::TestCase
assert_tag :tag => 'div', :attributes => { :class => /main-block/ }, :descendant => { :tag => 'a', :attributes => { :href => "/myprofile/testinguser/cms/edit/#{forum.id}" }, :content => 'Configure forum' }
end
+ should 'display add translation link if article is translatable' do
+ login_as @profile.identifier
+ textile = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'textile', :language => 'en')
+ get :view_page, :profile => @profile.identifier, :page => textile.explode_path
+ assert_tag :a, :attributes => { :href => "/myprofile/#{profile.identifier}/cms/new?article%5Btranslation_of_id%5D=#{textile.id}&type=#{TextileArticle}" }
+ end
+
+ should 'not display add translation link if article is not translatable' do
+ login_as @profile.identifier
+ blog = fast_create(Blog, :profile_id => @profile.id, :path => 'blog')
+ get :view_page, :profile => @profile.identifier, :page => blog.explode_path
+ assert_no_tag :a, :attributes => { :content => 'Add translation', :class => /icon-locale/ }
+ end
+
+ should 'not display add translation link if article hasnt a language defined' do
+ login_as @profile.identifier
+ textile = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'textile')
+ get :view_page, :profile => @profile.identifier, :page => textile.explode_path
+ assert_no_tag :a, :attributes => { :content => 'Add translation', :class => /icon-locale/ }
+ end
+
+ should 'diplay translations link if article has translations' do
+ login_as @profile.identifier
+ textile = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'textile', :language => 'en')
+ translation = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'translation', :language => 'es', :translation_of_id => textile)
+ get :view_page, :profile => @profile.identifier, :page => textile.explode_path
+ assert_tag :a, :attributes => { :class => /article-translations-menu/, :onclick => /toggleSubmenu/ }
+ end
+
+ should 'be redirected to translation if article is a root' do
+ @request.env['HTTP_REFERER'] = 'http://some.path'
+ FastGettext.stubs(:locale).returns('es')
+ en_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'en_article', :language => 'en')
+ es_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'es_article', :language => 'es', :translation_of_id => en_article)
+ get :view_page, :profile => @profile.identifier, :page => en_article.explode_path
+ assert_redirected_to :profile => @profile.identifier, :page => es_article.explode_path
+ assert_equal es_article, assigns(:page)
+ end
+
+ should 'be redirected to translation' do
+ @request.env['HTTP_REFERER'] = 'http://some.path'
+ FastGettext.stubs(:locale).returns('en')
+ en_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'en_article', :language => 'en')
+ es_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'es_article', :language => 'es', :translation_of_id => en_article)
+ get :view_page, :profile => @profile.identifier, :page => es_article.explode_path
+ assert_redirected_to :profile => @profile.identifier, :page => en_article.explode_path
+ assert_equal en_article, assigns(:page)
+ end
+
+ should 'not be redirected if already in translation' do
+ en_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'en_article', :language => 'en')
+ es_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'es_article', :language => 'es', :translation_of_id => en_article)
+ @request.env['HTTP_REFERER'] = "http://localhost:3000/#{@profile.identifier}/#{es_article.path}"
+ FastGettext.stubs(:locale).returns('es')
+ get :view_page, :profile => @profile.identifier, :page => es_article.explode_path
+ assert_response :success
+ assert_equal es_article, assigns(:page)
+ end
+
+ should 'not be redirected if article does not have a language' do
+ FastGettext.stubs(:locale).returns('es')
+ article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'article')
+ get :view_page, :profile => @profile.identifier, :page => article.explode_path
+ assert_response :success
+ assert_equal article, assigns(:page)
+ end
+
+ should 'not be redirected if http_referer is a translation' do
+ en_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'en_article', :language => 'en')
+ es_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'es_article', :language => 'es', :translation_of_id => en_article)
+ @request.env['HTTP_REFERER'] = "http://localhost:3000/#{@profile.identifier}/#{es_article.path}"
+ FastGettext.stubs(:locale).returns('es')
+ get :view_page, :profile => @profile.identifier, :page => en_article.explode_path
+ assert_response :success
+ assert_equal en_article, assigns(:page)
+ end
+
+ should 'be redirected if http_referer is nil' do
+ en_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'en_article', :language => 'en')
+ es_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'es_article', :language => 'es', :translation_of_id => en_article)
+ @request.env['HTTP_REFERER'] = nil
+ FastGettext.stubs(:locale).returns('es')
+ get :view_page, :profile => @profile.identifier, :page => en_article.explode_path
+ assert_redirected_to :profile => @profile.identifier, :page => es_article.explode_path
+ assert_equal es_article, assigns(:page)
+ end
+
+ should 'not be redirected to transition if came from edit' do
+ en_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'en_article', :language => 'en')
+ es_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'es_article', :language => 'es', :translation_of_id => en_article)
+ FastGettext.stubs(:locale).returns('es')
+ @request.env['HTTP_REFERER'] = "http://localhost/myprofile/#{@profile.identifier}/cms/edit/#{en_article.id}"
+ get :view_page, :profile => @profile.identifier, :page => es_article.explode_path
+ assert_response :success
+ assert_equal es_article, assigns(:page)
+ end
+
+ should 'not be redirected to transition if came from new' do
+ en_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'en_article', :language => 'en')
+ es_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'es_article', :language => 'es', :translation_of_id => en_article)
+ FastGettext.stubs(:locale).returns('es')
+ @request.env['HTTP_REFERER'] = "http://localhost/myprofile/#{@profile.identifier}/cms/new"
+ get :view_page, :profile => @profile.identifier, :page => es_article.explode_path
+ assert_response :success
+ assert_equal es_article, assigns(:page)
+ end
+
+ should 'replace article for his translation at blog listing if blog option is enabled' do
+ FastGettext.stubs(:locale).returns('es')
+ blog = fast_create(Blog, :profile_id => profile.id, :path => 'blog')
+ blog.stubs(:display_posts_in_current_language).returns(true)
+ en_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'en_article', :language => 'en')
+ es_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'es_article', :language => 'es', :translation_of_id => en_article)
+ blog.posts = [en_article, es_article]
+
+ get :view_page, :profile => @profile.identifier, :page => blog.explode_path
+ assert_tag :div, :attributes => { :id => "post-#{es_article.id}" }
+ assert_no_tag :div, :attributes => { :id => "post-#{en_article.id}" }
+ end
+
+ should 'list all posts at blog listing if blog option is disabled' do
+ FastGettext.stubs(:locale).returns('es')
+ blog = Blog.create!(:name => 'A blog test', :profile => profile, :display_posts_in_current_language => false)
+ blog.posts << es_post = TextileArticle.create!(:name => 'Spanish Post', :profile => profile, :parent => blog, :language => 'es')
+ blog.posts << en_post = TextileArticle.create!(:name => 'English Post', :profile => profile, :parent => blog, :language => 'en', :translation_of_id => es_post.id)
+ get :view_page, :profile => profile.identifier, :page => [blog.path]
+ assert_equal 2, assigns(:posts).size
+ assert_tag :div, :attributes => { :id => "post-#{es_post.id}" }
+ assert_tag :div, :attributes => { :id => "post-#{en_post.id}" }
+ end
+
+ should 'display only native translations at blog listing if blog option is enabled' do
+ FastGettext.stubs(:locale).returns('es')
+ blog = fast_create(Blog, :profile_id => profile.id, :path => 'blog')
+ blog.stubs(:display_posts_in_current_language).returns(true)
+ en_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'en_article', :language => 'en')
+ es_article = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'es_article', :language => 'es', :translation_of_id => en_article)
+ blog.posts = [en_article, es_article]
+
+ get :view_page, :profile => @profile.identifier, :page => blog.explode_path
+ assert_equal [es_article], assigns(:posts)
+ end
+
end
diff --git a/test/unit/article_test.rb b/test/unit/article_test.rb
index 09df4d9..daebd0b 100644
--- a/test/unit/article_test.rb
+++ b/test/unit/article_test.rb
@@ -1229,4 +1229,174 @@ class ArticleTest < Test::Unit::TestCase
assert_equal [g], p.articles.galleries
end
+ should 'has many translations' do
+ a = build(Article)
+ assert_raises(ActiveRecord::AssociationTypeMismatch) { a.translations << 1 }
+ assert_nothing_raised { a.translations << build(Article) }
+ end
+
+ should 'belongs to translation of' do
+ a = build(Article)
+ assert_raises(ActiveRecord::AssociationTypeMismatch) { a.translation_of = 1 }
+ assert_nothing_raised { a.translation_of = build(Article) }
+ end
+
+ should 'has language' do
+ a = build(Article)
+ assert_nothing_raised { a.language = 'en' }
+ end
+
+ should 'validade inclusion of language' do
+ a = build(Article)
+ a.language = '12'
+ a.valid?
+ assert a.errors.invalid?(:language)
+ a.language = 'en'
+ a.valid?
+ assert !a.errors.invalid?(:language)
+ end
+
+ should 'language can be blank' do
+ a = build(Article)
+ a.valid?
+ assert !a.errors.invalid?(:language)
+ a.language = ''
+ a.valid?
+ assert !a.errors.invalid?(:language)
+ end
+
+ should 'article is not translatable' do
+ a = build(Article)
+ assert !a.translatable?
+ end
+
+ should 'get native translation' do
+ native_article = fast_create(Article)
+ article_translation = fast_create(Article)
+ native_article.translations << article_translation
+ assert_equal native_article, native_article.native_translation
+ assert_equal native_article, article_translation.native_translation
+ end
+
+ should 'list possible translations' do
+ native_article = fast_create(Article, :language => 'pt')
+ article_translation = fast_create(Article, :language => 'en', :translation_of_id => native_article.id)
+ possible_translations = native_article.possible_translations
+ assert !possible_translations.include?('en')
+ assert possible_translations.include?('pt')
+ end
+
+ should 'verify if translation is already in use' do
+ native_article = fast_create(Article, :language => 'pt')
+ article_translation = fast_create(Article, :language => 'en', :translation_of_id => native_article.id)
+ a = build(Article)
+ a.language = 'en'
+ a.translation_of = native_article
+ a.valid?
+ assert a.errors.invalid?(:language)
+ a.language = 'es'
+ a.valid?
+ assert !a.errors.invalid?(:language)
+ end
+
+ should 'verify if native translation is already in use' do
+ native_article = fast_create(Article, :language => 'pt')
+ a = build(Article)
+ a.language = 'pt'
+ a.translation_of = native_article
+ a.valid?
+ assert a.errors.invalid?(:language)
+ a.language = 'es'
+ a.valid?
+ assert !a.errors.invalid?(:language)
+ end
+
+ should 'translation have a language' do
+ native_article = fast_create(Article, :language => 'pt')
+ a = build(Article)
+ a.translation_of = native_article
+ a.valid?
+ assert a.errors.invalid?(:language)
+ a.language = 'en'
+ a.valid?
+ assert !a.errors.invalid?(:language)
+ end
+
+ should 'native translation have a language' do
+ native_article = fast_create(Article)
+ a = build(Article)
+ a.language = 'en'
+ a.translation_of = native_article
+ a.valid?
+ n = a.errors.count
+ native_article.language = 'pt'
+ native_article.save
+ a.valid?
+ assert_equal n - 1, a.errors.count
+ end
+
+ should 'rotate translations when root article is destroyed' do
+ native_article = fast_create(Article, :language => 'pt', :profile_id => @profile.id)
+ translation1 = fast_create(Article, :language => 'en', :translation_of_id => native_article.id, :profile_id => @profile.id)
+ translation2 = fast_create(Article, :language => 'es', :translation_of_id => native_article.id, :profile_id => @profile.id)
+ native_article.destroy
+ assert translation1.translation_of.nil?
+ assert translation1.translations.include?(translation2)
+ end
+
+ should 'rotate one translation when root article is destroyed' do
+ native_article = fast_create(Article, :language => 'pt', :profile_id => @profile.id)
+ translation = fast_create(Article, :language => 'en', :translation_of_id => native_article.id, :profile_id => @profile.id)
+ native_article.destroy
+ assert translation.translation_of.nil?
+ assert translation.translations.empty?
+ end
+
+ should 'get self if article does not a language' do
+ article = fast_create(Article, :profile_id => @profile.id)
+ assert_equal article, article.get_translation_to('en')
+ end
+
+ should 'get self if article is the translation' do
+ article = fast_create(Article, :language => 'pt', :profile_id => @profile.id)
+ assert_equal article, article.get_translation_to('pt')
+ end
+
+ should 'get the native translation if it is the translation' do
+ native_article = fast_create(Article, :language => 'pt', :profile_id => @profile.id)
+ translation = fast_create(Article, :language => 'en', :translation_of_id => native_article.id, :profile_id => @profile.id)
+ assert_equal native_article, translation.get_translation_to('pt')
+ end
+
+ should 'get the translation if article has translation' do
+ native_article = fast_create(Article, :language => 'pt', :profile_id => @profile.id)
+ translation = fast_create(Article, :language => 'en', :translation_of_id => native_article.id, :profile_id => @profile.id)
+ assert_equal translation, native_article.get_translation_to('en')
+ end
+
+ should 'get self if article does not has a translation' do
+ native_article = fast_create(Article, :language => 'pt', :profile_id => @profile.id)
+ assert_equal native_article, native_article.get_translation_to('en')
+ end
+
+ should 'get only non translated articles' do
+ p = fast_create(Profile)
+ native = fast_create(Article, :language => 'pt', :profile_id => p.id)
+ translation = fast_create(Article, :language => 'en', :translation_of_id => native.id, :profile_id => p.id)
+ assert_equal [native], p.articles.native_translations
+ end
+
+ should 'not list own language as a possible translation if language has changed' do
+ a = build(Article, :language => 'pt')
+ assert !a.possible_translations.include?('pt')
+ a = fast_create(Article, :language => 'pt')
+ a.language = 'en'
+ assert !a.possible_translations.include?('en')
+ end
+
+ should 'list own language as a possible translation if language has not changed' do
+ a = fast_create(Article, :language => 'pt')
+ assert a.possible_translations.include?('pt')
+ end
+
end
diff --git a/test/unit/blog_archives_block_test.rb b/test/unit/blog_archives_block_test.rb
index 914bb8a..a15656c 100644
--- a/test/unit/blog_archives_block_test.rb
+++ b/test/unit/blog_archives_block_test.rb
@@ -102,4 +102,36 @@ class BlogArchivesBlockTest < ActiveSupport::TestCase
assert_no_match(/blog-two/m, block.content)
end
+ should 'list amount native posts by year' do
+ date = DateTime.parse('2008-01-01')
+ blog = profile.blog
+ 2.times do |i|
+ post = fast_create(TextileArticle, :name => "post #{i} test", :profile_id => profile.id,
+ :parent_id => blog.id, :language => 'en')
+ post.update_attribute(:published_at, date)
+ translation = fast_create(TextileArticle, :name => "post #{i} test", :profile_id => profile.id,
+ :parent_id => blog.id, :language => 'en', :translation_of_id => post.id)
+ translation.update_attribute(:published_at, date)
+ end
+ block = BlogArchivesBlock.new
+ block.stubs(:owner).returns(profile)
+ assert_tag_in_string block.content, :tag => 'li', :content => '2008 (2)'
+ end
+
+ should 'list amount native posts by month' do
+ date = DateTime.parse('2008-01-01')
+ blog = profile.blog
+ 2.times do |i|
+ post = fast_create(TextileArticle, :name => "post #{i} test", :profile_id => profile.id,
+ :parent_id => blog.id, :language => 'en')
+ post.update_attribute(:published_at, date)
+ translation = fast_create(TextileArticle, :name => "post #{i} test", :profile_id => profile.id,
+ :parent_id => blog.id, :language => 'en', :translation_of_id => post.id)
+ translation.update_attribute(:published_at, date)
+ end
+ block = BlogArchivesBlock.new
+ block.stubs(:owner).returns(profile)
+ assert_tag_in_string block.content, :tag => 'a', :content => 'January (2)', :attributes => {:href => /^http:\/\/.*\/flatline\/blog-one\?month=01&year=2008$/ }
+ end
+
end
diff --git a/test/unit/blog_test.rb b/test/unit/blog_test.rb
index 49bfd6b..13e1d63 100644
--- a/test/unit/blog_test.rb
+++ b/test/unit/blog_test.rb
@@ -175,4 +175,20 @@ class BlogTest < ActiveSupport::TestCase
assert Blog.new.has_posts?
end
+ should 'display posts in current language by default' do
+ blog = Blog.new
+ assert blog.display_posts_in_current_language
+ assert blog.display_posts_in_current_language?
+ end
+
+ should 'update display posts in current language setting' do
+ p = create_user('testuser').person
+ p.articles << Blog.new(:profile => p, :name => 'Blog test')
+ blog = p.blog
+ blog.display_posts_in_current_language = false
+ assert blog.save! && blog.reload
+ assert !blog.reload.display_posts_in_current_language
+ assert !blog.reload.display_posts_in_current_language?
+ end
+
end
diff --git a/test/unit/event_test.rb b/test/unit/event_test.rb
index c5f519c..678e842 100644
--- a/test/unit/event_test.rb
+++ b/test/unit/event_test.rb
@@ -265,4 +265,10 @@ class EventTest < ActiveSupport::TestCase
assert_match /
Wellformed html code <\/h1>/, event.description
assert_match / Wellformed html code <\/h1>/, event.address
end
+
+ should 'be translatable' do
+ e = Event.new
+ assert e.translatable?
+ end
+
end
diff --git a/test/unit/rss_feed_test.rb b/test/unit/rss_feed_test.rb
index 7d3d012..7b94eae 100644
--- a/test/unit/rss_feed_test.rb
+++ b/test/unit/rss_feed_test.rb
@@ -240,4 +240,24 @@ class RssFeedTest < Test::Unit::TestCase
assert_not_nil RssFeed.new.to_html
end
+ should 'include posts from all languages' do
+ profile = create_user('testuser').person
+ blog = Blog.create!(:name => 'blog-test', :profile => profile, :language => nil)
+ blog.posts << en_post = fast_create(TextArticle, :name => "English", :profile_id => profile.id, :parent_id => blog.id, :published => true, :language => 'en')
+ blog.posts << es_post = fast_create(TextArticle, :name => "Spanish", :profile_id => profile.id, :parent_id => blog.id, :published => true, :language => 'es')
+
+ assert blog.feed.fetch_articles.include?(en_post)
+ assert blog.feed.fetch_articles.include?(es_post)
+ end
+
+ should 'include only posts from some language' do
+ profile = create_user('testuser').person
+ blog = Blog.create!(:name => 'blog-test', :profile => profile)
+ blog.feed.update_attributes! :language => 'es'
+ blog.posts << en_post = fast_create(TextArticle, :name => "English", :profile_id => profile.id, :parent_id => blog.id, :published => true, :language => 'en')
+ blog.posts << es_post = fast_create(TextArticle, :name => "Spanish", :profile_id => profile.id, :parent_id => blog.id, :published => true, :language => 'es')
+
+ assert_equal [es_post], blog.feed.fetch_articles
+ end
+
end
diff --git a/test/unit/textile_article_test.rb b/test/unit/textile_article_test.rb
index 1c9629f..2060389 100644
--- a/test/unit/textile_article_test.rb
+++ b/test/unit/textile_article_test.rb
@@ -146,4 +146,9 @@ class TextileArticleTest < Test::Unit::TestCase
assert_equal false, a.is_trackable?
end
+ should 'be translatable' do
+ a = TextileArticle.new
+ assert a.translatable?
+ end
+
end
diff --git a/test/unit/tiny_mce_article_test.rb b/test/unit/tiny_mce_article_test.rb
index c4f3a84..ea639b8 100644
--- a/test/unit/tiny_mce_article_test.rb
+++ b/test/unit/tiny_mce_article_test.rb
@@ -237,5 +237,8 @@ class TinyMceArticleTest < Test::Unit::TestCase
assert_equal false, a.is_trackable?
end
-
+ should 'be translatable' do
+ a = TinyMceArticle.new
+ assert a.translatable?
+ end
end
--
libgit2 0.21.2