mongo_translatable 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +26 -0
- data/.gitmodules +3 -0
- data/LICENSE +295 -0
- data/README.rdoc +131 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/app/controllers/translations_controller.rb +150 -0
- data/app/helpers/translations_helper.rb +71 -0
- data/app/views/layouts/translations.html.erb +18 -0
- data/app/views/translations/_form.html.erb +50 -0
- data/app/views/translations/_translatable_value.html.erb +17 -0
- data/app/views/translations/_translation_field.html.erb +34 -0
- data/app/views/translations/_translation_field_input.html.erb +8 -0
- data/app/views/translations/edit.html.erb +8 -0
- data/app/views/translations/index.html.erb +22 -0
- data/app/views/translations/new.html.erb +7 -0
- data/app/views/translations/show.html.erb +12 -0
- data/config/locales/en.yml +33 -0
- data/config/locales/fr.yml +18 -0
- data/lib/mongo_translatable.rb +336 -0
- data/lib/mongo_translatable_configuration.rb +5 -0
- data/lib/translatables_helper.rb +227 -0
- data/lib/translations_controller_helpers.rb +37 -0
- data/rails/init.rb +3 -0
- data/test/full_2_3_5_app_with_tests/.gitignore +27 -0
- data/test/full_2_3_5_app_with_tests/README +1 -0
- data/test/full_2_3_5_app_with_tests/Rakefile +10 -0
- data/test/full_2_3_5_app_with_tests/app/controllers/application_controller.rb +26 -0
- data/test/full_2_3_5_app_with_tests/app/controllers/items_controller.rb +85 -0
- data/test/full_2_3_5_app_with_tests/app/helpers/application_helper.rb +3 -0
- data/test/full_2_3_5_app_with_tests/app/helpers/items_helper.rb +2 -0
- data/test/full_2_3_5_app_with_tests/app/models/comment.rb +3 -0
- data/test/full_2_3_5_app_with_tests/app/models/item.rb +5 -0
- data/test/full_2_3_5_app_with_tests/app/models/not_swapped_in_record.rb +3 -0
- data/test/full_2_3_5_app_with_tests/app/models/person.rb +3 -0
- data/test/full_2_3_5_app_with_tests/app/models/recipe.rb +21 -0
- data/test/full_2_3_5_app_with_tests/app/views/items/edit.html.erb +24 -0
- data/test/full_2_3_5_app_with_tests/app/views/items/index.html.erb +24 -0
- data/test/full_2_3_5_app_with_tests/app/views/items/new.html.erb +23 -0
- data/test/full_2_3_5_app_with_tests/app/views/items/show.html.erb +21 -0
- data/test/full_2_3_5_app_with_tests/app/views/layouts/items.html.erb +19 -0
- data/test/full_2_3_5_app_with_tests/config/boot.rb +110 -0
- data/test/full_2_3_5_app_with_tests/config/database.yml +22 -0
- data/test/full_2_3_5_app_with_tests/config/environment.rb +54 -0
- data/test/full_2_3_5_app_with_tests/config/environments/development.rb +17 -0
- data/test/full_2_3_5_app_with_tests/config/environments/production.rb +28 -0
- data/test/full_2_3_5_app_with_tests/config/environments/test.rb +28 -0
- data/test/full_2_3_5_app_with_tests/config/initializers/backtrace_silencers.rb +7 -0
- data/test/full_2_3_5_app_with_tests/config/initializers/inflections.rb +10 -0
- data/test/full_2_3_5_app_with_tests/config/initializers/mime_types.rb +5 -0
- data/test/full_2_3_5_app_with_tests/config/initializers/new_rails_defaults.rb +21 -0
- data/test/full_2_3_5_app_with_tests/config/initializers/session_store.rb +15 -0
- data/test/full_2_3_5_app_with_tests/config/locales.yml +5 -0
- data/test/full_2_3_5_app_with_tests/config/locales/en.yml +4 -0
- data/test/full_2_3_5_app_with_tests/config/locales/fr.yml +4 -0
- data/test/full_2_3_5_app_with_tests/config/locales/zh.yml +4 -0
- data/test/full_2_3_5_app_with_tests/config/routes.rb +4 -0
- data/test/full_2_3_5_app_with_tests/db/migrate/20100407010602_create_items.rb +14 -0
- data/test/full_2_3_5_app_with_tests/db/migrate/20100504234216_create_not_swapped_in_records.rb +15 -0
- data/test/full_2_3_5_app_with_tests/db/migrate/20100509011052_create_people.rb +13 -0
- data/test/full_2_3_5_app_with_tests/db/migrate/20100509042718_create_comments.rb +14 -0
- data/test/full_2_3_5_app_with_tests/db/migrate/20110112023516_create_recipes.rb +14 -0
- data/test/full_2_3_5_app_with_tests/db/schema.rb +56 -0
- data/test/full_2_3_5_app_with_tests/db/seeds.rb +7 -0
- data/test/full_2_3_5_app_with_tests/doc/README_FOR_APP +2 -0
- data/test/full_2_3_5_app_with_tests/public/404.html +30 -0
- data/test/full_2_3_5_app_with_tests/public/422.html +30 -0
- data/test/full_2_3_5_app_with_tests/public/500.html +30 -0
- data/test/full_2_3_5_app_with_tests/public/favicon.ico +0 -0
- data/test/full_2_3_5_app_with_tests/public/images/rails.png +0 -0
- data/test/full_2_3_5_app_with_tests/public/index.html +275 -0
- data/test/full_2_3_5_app_with_tests/public/javascripts/application.js +2 -0
- data/test/full_2_3_5_app_with_tests/public/javascripts/controls.js +963 -0
- data/test/full_2_3_5_app_with_tests/public/javascripts/dragdrop.js +973 -0
- data/test/full_2_3_5_app_with_tests/public/javascripts/effects.js +1128 -0
- data/test/full_2_3_5_app_with_tests/public/javascripts/prototype.js +4320 -0
- data/test/full_2_3_5_app_with_tests/public/robots.txt +5 -0
- data/test/full_2_3_5_app_with_tests/public/stylesheets/scaffold.css +54 -0
- data/test/full_2_3_5_app_with_tests/script/about +4 -0
- data/test/full_2_3_5_app_with_tests/script/console +3 -0
- data/test/full_2_3_5_app_with_tests/script/dbconsole +3 -0
- data/test/full_2_3_5_app_with_tests/script/destroy +3 -0
- data/test/full_2_3_5_app_with_tests/script/generate +3 -0
- data/test/full_2_3_5_app_with_tests/script/performance/benchmarker +3 -0
- data/test/full_2_3_5_app_with_tests/script/performance/profiler +3 -0
- data/test/full_2_3_5_app_with_tests/script/plugin +3 -0
- data/test/full_2_3_5_app_with_tests/script/runner +3 -0
- data/test/full_2_3_5_app_with_tests/script/server +3 -0
- data/test/full_2_3_5_app_with_tests/test/factories.rb +18 -0
- data/test/full_2_3_5_app_with_tests/test/functional/translations_controller_test.rb +66 -0
- data/test/full_2_3_5_app_with_tests/test/integration/translation_test.rb +72 -0
- data/test/full_2_3_5_app_with_tests/test/performance/browsing_test.rb +9 -0
- data/test/full_2_3_5_app_with_tests/test/selenium.rb +83 -0
- data/test/full_2_3_5_app_with_tests/test/test_helper.rb +86 -0
- data/test/full_2_3_5_app_with_tests/test/unit/helpers/translatables_helper_test.rb +37 -0
- data/test/full_2_3_5_app_with_tests/test/unit/helpers/translations_helper_test.rb +62 -0
- data/test/full_2_3_5_app_with_tests/test/unit/mongo_translatable_test.rb +342 -0
- data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/init.rb +1 -0
- data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter.rb +94 -0
- data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter/base.rb +31 -0
- data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter/force_extension.rb +57 -0
- data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter/locale.rb +70 -0
- data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter/pagination.rb +33 -0
- data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/lib/routing_filter/uuid_token.rb +78 -0
- data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/force_extension_spec.rb +65 -0
- data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/generation_spec.rb +367 -0
- data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/pagination_extension_spec.rb +19 -0
- data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/recognition_spec.rb +76 -0
- data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/routing_filter_spec.rb +114 -0
- data/test/full_2_3_5_app_with_tests/vendor/plugins/routing-filter/spec/spec_helper.rb +108 -0
- metadata +309 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
require 'test_helper'
|
|
3
|
+
|
|
4
|
+
class TranslatablesHelperTest < ActionView::TestCase
|
|
5
|
+
context "Helpers for translatables" do
|
|
6
|
+
setup do
|
|
7
|
+
I18n.locale = I18n.default_locale
|
|
8
|
+
@item = Factory.create(:item, :label => "a label")
|
|
9
|
+
@translatable_params_name = "item"
|
|
10
|
+
|
|
11
|
+
def url_for_translated(options = { })
|
|
12
|
+
@controller.url_for_translated(options.merge(
|
|
13
|
+
:translated => @item,
|
|
14
|
+
:translatable_params_name => @translatable_params_name
|
|
15
|
+
))
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# TODO: current request need to be in environment for this to run
|
|
20
|
+
should "have provide available_in_locales_for that returns current translations for passed in item as list" do
|
|
21
|
+
@item.translate(:label => 'une étiquette', :locale => 'fr').save
|
|
22
|
+
html = "<ul><li><a href=\"/fr/items/1\">Français</li></ul>"
|
|
23
|
+
assert_equal html, available_in_locales_for(@item)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
should "have provide needed_in_locales_for that returns current locales that don't have a translation for passed in item as list" do
|
|
27
|
+
locales = LOCALE_LABELS.keys - [:zh, :en]
|
|
28
|
+
translate_item_for_locales(@item, locales)
|
|
29
|
+
html = "<ul style='list-style:none; margin:0; padding:0;'>"
|
|
30
|
+
html += "<li style='float:left;'>Needs translating to:</li>"
|
|
31
|
+
html += "<li style=\"float: left; padding: 0 10px; \"><a href=\"/en/items/1/translations/new?to_locale=zh\">中文</a></li>"
|
|
32
|
+
html += "</ul><div style='clear:both;'></div>"
|
|
33
|
+
I18n.locale = I18n.default_locale
|
|
34
|
+
assert_equal html, needed_in_locales_for(@item)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
require 'test_helper'
|
|
3
|
+
|
|
4
|
+
class TranslationsHelperTest < ActionView::TestCase
|
|
5
|
+
context "Helpers for translation" do
|
|
6
|
+
setup do
|
|
7
|
+
I18n.locale = I18n.default_locale
|
|
8
|
+
@translatable = Factory.create(:item, :label => "a label")
|
|
9
|
+
@translatable_class = Item
|
|
10
|
+
@translatable_key = :item_id
|
|
11
|
+
@translatable_params_name = "item"
|
|
12
|
+
|
|
13
|
+
def url_for_translated(options = { })
|
|
14
|
+
@controller.url_for_translated(options.merge(
|
|
15
|
+
:translated => @translatable,
|
|
16
|
+
:translatable_params_name => @translatable_params_name
|
|
17
|
+
))
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
should "have avalailable_locales_for_options" do
|
|
22
|
+
locale_options = [["Français", "fr"],
|
|
23
|
+
["中文", "zh"],
|
|
24
|
+
["Suomi", "fi"],
|
|
25
|
+
["العربية", "ar"],
|
|
26
|
+
["English", "en"]]
|
|
27
|
+
assert_equal locale_options, available_locales_for_options
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
should "have provide available_in_locales that returns current translations for @translatable as list" do
|
|
31
|
+
@translatable.translate(:label => 'une étiquette', :locale => 'fr').save
|
|
32
|
+
html = "<ul><li><a href=\"http://test.host/en/items/1\">English</a></li><li><a href=\"http://test.host/fr/items/1\">Français</a></li></ul>"
|
|
33
|
+
assert_equal html, available_in_locales
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
should "have provide needed_in_locales that returns current locales that don't have a translation for @translatable as list" do
|
|
37
|
+
locales = LOCALE_LABELS.keys - [:zh, :en]
|
|
38
|
+
translate_item_for_locales(@translatable, locales)
|
|
39
|
+
html = "<ul><li><a href=\"/en/items/1/translations/new?to_locale=zh\">中文</a></li></ul>"
|
|
40
|
+
I18n.locale = I18n.default_locale
|
|
41
|
+
assert_equal html, needed_in_locales
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
should "take attribute_key and give localized label" do
|
|
45
|
+
assert_equal "Label", localized_label_for(:label)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
should "take translatable and output internationalized html to display the original text of the attributes" do
|
|
49
|
+
array_with_hashes_of_translatable_attributes_with_internationalized_names = [{:attribute_key=>:label, :localized_label => "Label", :value => "a label"}]
|
|
50
|
+
# ignoring description for now (thus wrapped in array and .first)
|
|
51
|
+
assert_equal array_with_hashes_of_translatable_attributes_with_internationalized_names, [untranslated_values_with_localized_labels.first]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
should "take translation and output internationalized html to display the translated text of the attributes" do
|
|
55
|
+
@translatable.translate(:label => 'une étiquette', :locale => 'fr').save
|
|
56
|
+
@translation = @translatable.translation_for(:fr)
|
|
57
|
+
array_with_hashes_of_translated_attributes_with_internationalized_names = [{:attribute_key=>:label, :localized_label => "Label", :value => "une étiquette"}]
|
|
58
|
+
# ignoring description for now (thus wrapped in array and .first)
|
|
59
|
+
assert_equal array_with_hashes_of_translated_attributes_with_internationalized_names, [translated_values_with_localized_labels.first]
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
require 'test_helper'
|
|
3
|
+
|
|
4
|
+
class MongodbTranslatableTest < ActiveSupport::TestCase
|
|
5
|
+
context "A translation" do
|
|
6
|
+
setup do
|
|
7
|
+
I18n.locale = I18n.default_locale
|
|
8
|
+
|
|
9
|
+
@item = Factory.create(:item)
|
|
10
|
+
|
|
11
|
+
item_hash = Hash.new
|
|
12
|
+
item_hash[:label] = @item.attributes['label']
|
|
13
|
+
item_hash[:locale] = :fr
|
|
14
|
+
item_hash[@item.class.as_foreign_key_sym] = @item.id
|
|
15
|
+
@translation = @item.class::Translation.create(item_hash)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
should "have a locale" do
|
|
19
|
+
if assert(@translation.respond_to?(:locale))
|
|
20
|
+
assert @translation.locale
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
should "have a translated object's translated attributes" do
|
|
25
|
+
assert @translation.attributes[Item.translatable_attributes.first]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
should "be accessable from its item" do
|
|
29
|
+
if assert(@item.respond_to?(:translations))
|
|
30
|
+
assert @item.translation_for(I18n.locale)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
should "be able to retrieve just the translated attribute" do
|
|
35
|
+
if assert(@item.respond_to?(:translations) && @item.respond_to?(:label_translation_for))
|
|
36
|
+
assert @item.label_translation_for(I18n.locale)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
should "be able to retrieve its item from the item's persistence" do
|
|
41
|
+
assert @translation.translatable
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
context "When there is an Item needing translating" do
|
|
46
|
+
setup do
|
|
47
|
+
@item = Factory.create(:item, { :label => LOCALE_LABELS[:en] })
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
should "create translation" do
|
|
51
|
+
translate_item_for_locales(@item, :zh)
|
|
52
|
+
assert @item.translations.count == 1
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
should "not create translation if no translated text submitted" do
|
|
56
|
+
# arabic
|
|
57
|
+
I18n.locale = :ar
|
|
58
|
+
@item.translate
|
|
59
|
+
assert @item.translations.count == 0
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
should "not create translation if item's original_locale is same as translation locale" do
|
|
63
|
+
I18n.locale = :en
|
|
64
|
+
@item.translate(:label => LOCALE_LABELS[:en])
|
|
65
|
+
assert @item.translations.count == 0
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
should "create translation and it should reflect current locale" do
|
|
69
|
+
# french
|
|
70
|
+
translate_item_for_locales(@item, :fr)
|
|
71
|
+
assert @item.translation_for(:fr)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
should "find item with the proper translation for current locale" do
|
|
75
|
+
translate_item_for_locales(@item, :fi)
|
|
76
|
+
|
|
77
|
+
# reloading item should detect current locale and pass back translated version of object
|
|
78
|
+
@item = Item.find(@item.id)
|
|
79
|
+
|
|
80
|
+
assert_equal @item.label, LOCALE_LABELS[:fi]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
should "find item with the proper translation for current locale and fallback to original's value for translatable attribute that hasn't been translated" do
|
|
84
|
+
translate_item_for_locales(@item, :fi)
|
|
85
|
+
|
|
86
|
+
original_description = @item.description
|
|
87
|
+
|
|
88
|
+
# reloading item should detect current locale and pass back translated version of object
|
|
89
|
+
@item = Item.find(@item.id)
|
|
90
|
+
|
|
91
|
+
assert_equal @item.label, LOCALE_LABELS[:fi]
|
|
92
|
+
assert_equal original_description, @item.description
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
should "find item with the proper translation for current locale when there is more than one translation" do
|
|
96
|
+
# add a couple translations
|
|
97
|
+
translate_item_for_locales(@item, [:fi, :fr])
|
|
98
|
+
|
|
99
|
+
# then back to finnish
|
|
100
|
+
I18n.locale = :fi
|
|
101
|
+
|
|
102
|
+
# reloading item should detect current locale and pass back translated version of object
|
|
103
|
+
@item = Item.find(@item.id)
|
|
104
|
+
|
|
105
|
+
assert_equal @item.label, LOCALE_LABELS[:fi]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# test dynamic finder
|
|
109
|
+
should "find item with the proper translation for current locale when there is more than one translation and finding using dynamic finder" do
|
|
110
|
+
@item = Factory.create(:item, {:value => "a value"})
|
|
111
|
+
|
|
112
|
+
# add a couple translations
|
|
113
|
+
translate_item_for_locales(@item, [:fi, :fr])
|
|
114
|
+
|
|
115
|
+
# then back to finnish
|
|
116
|
+
I18n.locale = :fi
|
|
117
|
+
|
|
118
|
+
# reloading item should detect current locale and pass back translated version of object
|
|
119
|
+
@item = Item.find_by_value(@item.value)
|
|
120
|
+
|
|
121
|
+
assert_equal @item.label, LOCALE_LABELS[:fi]
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
should "after creating translations, if the item is destroyed, the translations are destroyed" do
|
|
125
|
+
# add a couple translations
|
|
126
|
+
translate_item_for_locales(@item, [:fi, :fr])
|
|
127
|
+
|
|
128
|
+
translations_ids = @item.translations.collect { |translation| translation.id }
|
|
129
|
+
|
|
130
|
+
@item.destroy
|
|
131
|
+
|
|
132
|
+
remaining_translations = Item::Translation.find(translations_ids)
|
|
133
|
+
|
|
134
|
+
assert_equal 0, remaining_translations.size
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
should "when the item is destroyed, when it has no translations, it should succeed in being destroyed" do
|
|
138
|
+
assert_equal 0, @item.translations.size
|
|
139
|
+
assert @item.destroy
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
teardown do
|
|
143
|
+
I18n.locale = @original_locale
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
context "When there are many items being translated" do
|
|
148
|
+
setup do
|
|
149
|
+
# TODO: pull out this locale, not sure why before_save filter is not being called
|
|
150
|
+
@original_locale = I18n.locale
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
should "find items with the proper translation for current locale" do
|
|
154
|
+
ids = many_setup
|
|
155
|
+
|
|
156
|
+
# reloading item should detect current locale and pass back translated version of object
|
|
157
|
+
@items = Item.find(ids)
|
|
158
|
+
|
|
159
|
+
many_tests
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
should "find items with the proper translation for current locale using dynamic finder" do
|
|
163
|
+
value = "a value"
|
|
164
|
+
many_setup({:value => value})
|
|
165
|
+
|
|
166
|
+
# reloading item should detect current locale and pass back translated version of object
|
|
167
|
+
@items = Item.find_all_by_value(value)
|
|
168
|
+
|
|
169
|
+
many_tests(:fi => 10)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
teardown do
|
|
173
|
+
I18n.locale = @original_locale
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
context "translations for an item" do
|
|
178
|
+
setup do
|
|
179
|
+
I18n.locale = I18n.default_locale
|
|
180
|
+
@item = Factory.create(:item)
|
|
181
|
+
@translation_keys = LOCALE_LABELS.keys - [:en]
|
|
182
|
+
translate_item_for_locales(@item, @translation_keys)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
should "be retrievable from translations method" do
|
|
186
|
+
assert_equal @translation_keys.size, @item.translations.size
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
should "hae just locales be retrievable from translations_locales method" do
|
|
190
|
+
# these should be partial objects and not have any values for other attributes
|
|
191
|
+
locale_keys = @item.translations_locales.collect { |translation| translation.locale.to_sym if translation.label.nil? }.compact
|
|
192
|
+
|
|
193
|
+
assert_equal 0, (@translation_keys - locale_keys).size
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
should "have translation locales plus original local be retrievable as available_in_these_locales" do
|
|
197
|
+
locale_keys = @item.available_in_these_locales.collect { |locale| locale.to_sym }
|
|
198
|
+
|
|
199
|
+
assert_equal 0, ( ([:en] + @translation_keys) - locale_keys ).size
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
should "have needed_in_these_locales method that returns locales that haven't been translated yet" do
|
|
203
|
+
Item::Translation.first(:item_id => @item.id, :locale => "zh").destroy
|
|
204
|
+
assert_equal [:zh], @item.needed_in_these_locales.collect { |locale| locale.to_sym }
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
context "A Translatable class that has a plural associated accessors (has_many) in another class through an association" do
|
|
209
|
+
setup do
|
|
210
|
+
I18n.locale = I18n.default_locale
|
|
211
|
+
|
|
212
|
+
@person = Factory.create(:person)
|
|
213
|
+
@item1 = Factory.create(:item, :person => @person)
|
|
214
|
+
@item2 = Factory.create(:item, :person => @person)
|
|
215
|
+
|
|
216
|
+
translate_item_for_locales(@item1, :fr)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
should "get translated results from plural accessor" do
|
|
220
|
+
I18n.locale = :fr
|
|
221
|
+
results_with_one_translated_labels = [@item1.reload, @item2].collect(&:label)
|
|
222
|
+
|
|
223
|
+
assert_equal results_with_one_translated_labels, @person.items.collect(&:label)
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
context "A Translatable class that has a singular associated accessor (belongs_to, has_one) in another class through an association" do
|
|
228
|
+
setup do
|
|
229
|
+
I18n.locale = I18n.default_locale
|
|
230
|
+
|
|
231
|
+
@item = Factory.create(:item, :person => @person)
|
|
232
|
+
@comment = @item.comments.create(:subject => "usual mallarky")
|
|
233
|
+
|
|
234
|
+
translate_item_for_locales(@item, :fr)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
should "get translated results from singular accessor" do
|
|
238
|
+
I18n.locale = :fr
|
|
239
|
+
translated_label = Item.find(@item).label
|
|
240
|
+
assert_equal translated_label, @comment.item.label
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
context "A Translatable class that has redefine_find == false" do
|
|
245
|
+
setup do
|
|
246
|
+
I18n.locale = I18n.default_locale
|
|
247
|
+
@record = Factory.create(:not_swapped_in_record)
|
|
248
|
+
record_hash = Hash.new
|
|
249
|
+
record_hash[:name] = @record.attributes['name']
|
|
250
|
+
record_hash[:locale] = :fr
|
|
251
|
+
record_hash[@record.class.as_foreign_key_sym] = @record.id
|
|
252
|
+
@no_find_translation = @record.class::Translation.create(record_hash)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
should "not swap out locale specific translation for record when loaded from a translated locale" do
|
|
256
|
+
I18n.locale = :fr
|
|
257
|
+
@record.reload
|
|
258
|
+
assert_equal 'en', @record.locale
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
context "A Translatable class that has some translatable_attributes with key_type specified" do
|
|
263
|
+
|
|
264
|
+
should "have String for type of key without key_type specified (default)" do
|
|
265
|
+
assert_equal Recipe::Translation.keys['name'].type, String
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
should "have Array for type of key when " do
|
|
269
|
+
assert_equal Recipe::Translation.keys['steps'].type, Array
|
|
270
|
+
assert_equal Recipe::Translation.keys['ingredients'].type, Array
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
context "can create translations that" do
|
|
274
|
+
setup do
|
|
275
|
+
I18n.locale = I18n.default_locale
|
|
276
|
+
@recipe = Factory.create(:recipe)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
should "return value in correct key type for translatable_attribute" do
|
|
280
|
+
assert_equal @recipe.steps, ["steps1 - 1", "steps1 - 2"]
|
|
281
|
+
assert_equal @recipe.ingredients, ["ingredients1 - 1", "ingredients1 - 2"]
|
|
282
|
+
|
|
283
|
+
fr_steps = ['fr step 1', 'fr step 2']
|
|
284
|
+
fr_ingredients = ['fr ingredient 1', 'fr ingredient 2']
|
|
285
|
+
|
|
286
|
+
@recipe_translation = @recipe.class::Translation.create(:name => @recipe.attributes['name'],
|
|
287
|
+
:steps => fr_steps,
|
|
288
|
+
:ingredients => fr_ingredients,
|
|
289
|
+
:locale => :fr,
|
|
290
|
+
@recipe.class.as_foreign_key_sym => @recipe.id)
|
|
291
|
+
|
|
292
|
+
@recipe_translation.reload
|
|
293
|
+
|
|
294
|
+
assert_equal fr_steps, @recipe_translation.steps
|
|
295
|
+
assert_equal fr_ingredients, @recipe_translation.ingredients
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
private
|
|
302
|
+
|
|
303
|
+
# see many_tests for what it expects
|
|
304
|
+
def many_setup(item_spec = nil)
|
|
305
|
+
ids = Array.new
|
|
306
|
+
5.times do
|
|
307
|
+
I18n.locale = @original_locale
|
|
308
|
+
item = item_spec ? Factory.create(:item, item_spec) : Factory.create(:item)
|
|
309
|
+
translate_item_for_locales(item, [:ar, :fr])
|
|
310
|
+
ids << item.id
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
5.times do
|
|
314
|
+
I18n.locale = @original_locale
|
|
315
|
+
item = item_spec ? Factory.create(:item, item_spec) : Factory.create(:item)
|
|
316
|
+
translate_item_for_locales(item, [:zh, :fi])
|
|
317
|
+
ids << item.id
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
# excluding these from ids searched
|
|
321
|
+
5.times do
|
|
322
|
+
I18n.locale = @original_locale
|
|
323
|
+
item = item_spec ? Factory.create(:item, item_spec) : Factory.create(:item)
|
|
324
|
+
translate_item_for_locales(item, [:fr, :fi])
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
I18n.locale = :fi
|
|
328
|
+
ids
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
# expect 5 en, 5 finnish, and none in french, chinese, or arabic
|
|
332
|
+
def many_tests(passed_amounts = { })
|
|
333
|
+
results_number_for = { :fi => 5, :en => 5, :fr => 0, :ar => 0, :zh => 0}
|
|
334
|
+
results_number_for.merge!(passed_amounts)
|
|
335
|
+
|
|
336
|
+
assert_equal results_number_for[:fi], @items.select { |i| i.locale.to_sym == :fi }.size
|
|
337
|
+
assert_equal results_number_for[:en], @items.select { |i| i.locale.to_sym == :en }.size
|
|
338
|
+
assert_equal results_number_for[:fr], @items.select { |i| i.locale.to_sym == :fr }.size
|
|
339
|
+
assert_equal results_number_for[:ar], @items.select { |i| i.locale.to_sym == :ar }.size
|
|
340
|
+
assert_equal results_number_for[:zh], @items.select { |i| i.locale.to_sym == :zh }.size
|
|
341
|
+
end
|
|
342
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'routing_filter'
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
module RoutingFilter
|
|
2
|
+
mattr_accessor :active
|
|
3
|
+
@@active = true
|
|
4
|
+
|
|
5
|
+
class Chain < Array
|
|
6
|
+
def << (filter)
|
|
7
|
+
filter.chain = self
|
|
8
|
+
super
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def run(method, *args, &final)
|
|
12
|
+
RoutingFilter.active && !first.nil? ? first.run(method, *args, &final) : final.call
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def run_reverse(method, *args, &final)
|
|
16
|
+
RoutingFilter.active && !last.nil? ? last.run_reverse(method, *args, &final) : final.call
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def predecessor(filter)
|
|
20
|
+
ix = index(filter)
|
|
21
|
+
ix > 0 ? self[ix - 1] : nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def successor(filter)
|
|
25
|
+
ix = index(filter)
|
|
26
|
+
ix < length - 1 ? self[ix + 1] : nil
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# allows to install a filter to the route set by calling: map.filter 'locale'
|
|
32
|
+
ActionController::Routing::RouteSet::Mapper.class_eval do
|
|
33
|
+
def filter(name, options = {})
|
|
34
|
+
require options.delete(:file) || "routing_filter/#{name}"
|
|
35
|
+
klass = RoutingFilter.const_get(name.to_s.camelize)
|
|
36
|
+
@set.filters << klass.new(options)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# same here for the optimized url generation in named routes
|
|
41
|
+
ActionController::Routing::RouteSet::NamedRouteCollection.class_eval do
|
|
42
|
+
# gosh. monkey engineering optimization code
|
|
43
|
+
def generate_optimisation_block_with_filtering(*args)
|
|
44
|
+
code = generate_optimisation_block_without_filtering(*args)
|
|
45
|
+
if match = code.match(%r(^return (.*) if (.*)))
|
|
46
|
+
# returned string must not contain newlines, or we'll spill out of inline code comments in
|
|
47
|
+
# ActionController::Routing::RouteSet::NamedRouteCollection#define_url_helper
|
|
48
|
+
"returning(#{match[1]}) { |result|" +
|
|
49
|
+
" ActionController::Routing::Routes.filters.run_reverse(:around_generate, *args, &lambda{ result }) " +
|
|
50
|
+
"} if #{match[2]}"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
alias_method_chain :generate_optimisation_block, :filtering
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
ActionController::Routing::RouteSet.class_eval do
|
|
57
|
+
def clear_with_filtering!
|
|
58
|
+
@filters.clear if @filters
|
|
59
|
+
clear_without_filtering!
|
|
60
|
+
end
|
|
61
|
+
alias_method_chain :clear!, :filtering
|
|
62
|
+
|
|
63
|
+
attr_writer :filters
|
|
64
|
+
|
|
65
|
+
def filters
|
|
66
|
+
@filters ||= RoutingFilter::Chain.new
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def recognize_path_with_filtering(path, env = {})
|
|
70
|
+
path = ::URI.unescape(path.dup) # string is frozen due to memoize
|
|
71
|
+
filters.run(:around_recognize, path, env, &lambda{ recognize_path_without_filtering(path, env) })
|
|
72
|
+
end
|
|
73
|
+
alias_method_chain :recognize_path, :filtering
|
|
74
|
+
|
|
75
|
+
def generate_with_filtering(*args)
|
|
76
|
+
filters.run_reverse(:around_generate, args.first, &lambda{ generate_without_filtering(*args) })
|
|
77
|
+
end
|
|
78
|
+
alias_method_chain :generate, :filtering
|
|
79
|
+
|
|
80
|
+
# add some useful information to the request environment
|
|
81
|
+
# right, this is from jamis buck's excellent article about routes internals
|
|
82
|
+
# http://weblog.jamisbuck.org/2006/10/26/monkey-patching-rails-extending-routes-2
|
|
83
|
+
# TODO move this ... where?
|
|
84
|
+
alias_method :extract_request_environment_without_host, :extract_request_environment unless method_defined? :extract_request_environment_without_host
|
|
85
|
+
def extract_request_environment(request)
|
|
86
|
+
returning extract_request_environment_without_host(request) do |env|
|
|
87
|
+
env.merge! :host => request.host,
|
|
88
|
+
:port => request.port,
|
|
89
|
+
:host_with_port => request.host_with_port,
|
|
90
|
+
:domain => request.domain,
|
|
91
|
+
:subdomain => request.subdomains.first
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|