motiro 0.6.3
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/LICENSE +280 -0
- data/README +28 -0
- data/README.en +175 -0
- data/README.pt-br +175 -0
- data/Rakefile +10 -0
- data/app/controllers/account_controller.rb +62 -0
- data/app/controllers/application.rb +72 -0
- data/app/controllers/edition_controller.rb +13 -0
- data/app/controllers/javascript_controller.rb +21 -0
- data/app/controllers/report_controller.rb +79 -0
- data/app/controllers/root_controller.rb +7 -0
- data/app/controllers/wiki_controller.rb +102 -0
- data/app/core/cache_reporter.rb +53 -0
- data/app/core/cache_reporter_fetcher.rb +33 -0
- data/app/core/chief_editor.rb +69 -0
- data/app/core/reporter.rb +105 -0
- data/app/core/reporter_driver.rb +36 -0
- data/app/core/reporter_fetcher.rb +39 -0
- data/app/core/settings.rb +43 -0
- data/app/core/version.rb +1 -0
- data/app/core/wiki_page_not_found.rb +33 -0
- data/app/core/wiki_reporter.rb +83 -0
- data/app/helpers/account_helper.rb +2 -0
- data/app/helpers/application_helper.rb +68 -0
- data/app/helpers/default_page_provider.rb +28 -0
- data/app/helpers/report_helper.rb +2 -0
- data/app/helpers/root_helper.rb +2 -0
- data/app/helpers/wiki_helper.rb +3 -0
- data/app/models/change.rb +96 -0
- data/app/models/diff_table_builder.rb +285 -0
- data/app/models/event.rb +18 -0
- data/app/models/headline.rb +109 -0
- data/app/models/page.rb +114 -0
- data/app/models/page_sweeper.rb +26 -0
- data/app/models/user.rb +85 -0
- data/app/ports/chdir_runner.rb +36 -0
- data/app/ports/reporter_loader.rb +9 -0
- data/app/ports/runner.rb +64 -0
- data/app/reporters/darcs_connection.rb +54 -0
- data/app/reporters/darcs_reporter.rb +104 -0
- data/app/reporters/darcs_settings.rb +9 -0
- data/app/reporters/darcs_temp_repo.rb +40 -0
- data/app/reporters/events_reporter.rb +28 -0
- data/app/reporters/features_reporter.rb +24 -0
- data/app/reporters/subversion_reporter.rb +203 -0
- data/app/reporters/svn_connection.rb +62 -0
- data/app/reporters/svn_settings.rb +40 -0
- data/app/views/account/_authorization.rhtml +54 -0
- data/app/views/account/_availability.rhtml +5 -0
- data/app/views/account/availability.rhtml +1 -0
- data/app/views/account/login.rhtml +22 -0
- data/app/views/account/logout.rhtml +10 -0
- data/app/views/javascript/motiro.rjs +132 -0
- data/app/views/javascript/niftycube.rjs +300 -0
- data/app/views/layouts/_bottom.rhtml +5 -0
- data/app/views/layouts/_header.rhtml +7 -0
- data/app/views/layouts/_top.rhtml +25 -0
- data/app/views/layouts/application.rhtml +3 -0
- data/app/views/layouts/scaffold.rhtml +13 -0
- data/app/views/layouts/wiki_edit.rhtml +26 -0
- data/app/views/report/list.rhtml +32 -0
- data/app/views/report/older.rhtml +26 -0
- data/app/views/report/rss.rxml +29 -0
- data/app/views/report/show.rhtml +20 -0
- data/app/views/root/index.rhtml +33 -0
- data/app/views/wiki/_editbar.rhtml +26 -0
- data/app/views/wiki/_properties_edit.rhtml +5 -0
- data/app/views/wiki/_properties_show.rhtml +5 -0
- data/app/views/wiki/edit.rhtml +56 -0
- data/app/views/wiki/properties_edit.rhtml +1 -0
- data/app/views/wiki/show.rhtml +9 -0
- data/bin/motiro +44 -0
- data/config/boot.rb +19 -0
- data/config/database.yml +14 -0
- data/config/environment.rb +64 -0
- data/config/environments/development.rb +20 -0
- data/config/environments/production.rb +19 -0
- data/config/environments/test.rb +19 -0
- data/config/motiro.yml +43 -0
- data/config/routes.rb +79 -0
- data/db/migrate/005_globalize_migration.rb +11363 -0
- data/db/migrate/006_remove_headline_title.rb +14 -0
- data/db/migrate/007_stretch_rid.rb +11 -0
- data/db/migrate/008_add_page_editors.rb +12 -0
- data/db/migrate/009_add_page_original_author.rb +12 -0
- data/db/migrate/010_remove_empty_string_defaults_from_pages.rb +17 -0
- data/db/migrate/011_add_title_and_kind_to_pages.rb +13 -0
- data/db/migrate/012_page_modification_info.rb +13 -0
- data/db/migrate/013_nullify_initial_page_attributes.rb +21 -0
- data/db/migrate/014_events_are_wiki_pages.rb +13 -0
- data/db/migrate/015_migrate_previous_event_data.rb +23 -0
- data/db/migrate/1_initial_structure.rb +36 -0
- data/db/migrate/2_add_authentication.rb +12 -0
- data/db/migrate/3_drop_articles.rb +26 -0
- data/db/migrate/4_add_page_editing.rb +14 -0
- data/db/motirodb.sqlite.initial +0 -0
- data/db/schema_version +1 -0
- data/db/translation/pt-BR.rb +76 -0
- data/doc/README_FOR_APP +2 -0
- data/installer/rails_installer_defaults.yml +5 -0
- data/lib/import_translations.rb +154 -0
- data/lib/login_system.rb +89 -0
- data/lib/relative_time.rb +48 -0
- data/lib/string_extensions.rb +10 -0
- data/lib/stub_hash.rb +22 -0
- data/lib/tasks/packaging.rake +93 -0
- data/lib/tasks/testing.rake +32 -0
- data/lib/tick_daemon.rb +41 -0
- data/lib/translator.rb +67 -0
- data/lib/wiki_renderer.rb +42 -0
- data/lib/wiki_url_generator.rb +29 -0
- data/log/.keepdir +0 -0
- data/public/404.html +8 -0
- data/public/500.html +8 -0
- data/public/dispatch.cgi +10 -0
- data/public/dispatch.fcgi +24 -0
- data/public/dispatch.rb +10 -0
- data/public/favicon.ico +0 -0
- data/public/images/calendar.png +0 -0
- data/public/images/rss.png +0 -0
- data/public/javascripts/controls.js +750 -0
- data/public/javascripts/dragdrop.js +584 -0
- data/public/javascripts/effects.js +854 -0
- data/public/javascripts/prototype.js +1785 -0
- data/public/robots.txt +1 -0
- data/public/stylesheets/motiro.css +269 -0
- data/public/stylesheets/niftyCorners.css +35 -0
- data/public/stylesheets/scaffold.css +74 -0
- data/script/about +3 -0
- data/script/breakpointer +3 -0
- data/script/console +3 -0
- data/script/destroy +3 -0
- data/script/generate +3 -0
- data/script/performance/benchmarker +3 -0
- data/script/performance/profiler +3 -0
- data/script/plugin +3 -0
- data/script/process/reaper +3 -0
- data/script/process/spawner +3 -0
- data/script/process/spinner +3 -0
- data/script/runner +3 -0
- data/script/server +3 -0
- data/script/ticker +29 -0
- data/test/acceptance/account_test.rb +186 -0
- data/test/acceptance/darcs_test.rb +62 -0
- data/test/acceptance/events_test.rb +47 -0
- data/test/acceptance/main_page_test.rb +92 -0
- data/test/acceptance/subversion_test.rb +319 -0
- data/test/acceptance/ts_all_suites.rb +27 -0
- data/test/acceptance/wiki_test.rb +202 -0
- data/test/contract/darcs_test.rb +51 -0
- data/test/contract/remote_darcs_test.rb +61 -0
- data/test/contract/svn_test.rb +53 -0
- data/test/fixtures/changes.yml +25 -0
- data/test/fixtures/headlines.yml +45 -0
- data/test/fixtures/pages.yml +98 -0
- data/test/fixtures/users.yml +31 -0
- data/test/functional/account_controller_test.rb +96 -0
- data/test/functional/report_controller_test.rb +113 -0
- data/test/functional/report_features_test.rb +38 -0
- data/test/functional/report_subversion_test.rb +79 -0
- data/test/functional/root_controller_test.rb +127 -0
- data/test/functional/wiki_controller_test.rb +280 -0
- data/test/lib/acceptance_test_case.rb +43 -0
- data/test/lib/configuration.rb +53 -0
- data/test/lib/darcs_excerpts.rb +181 -0
- data/test/lib/darcs_repo.rb +77 -0
- data/test/lib/live_mode_test.rb +51 -0
- data/test/lib/local_svn.rb +157 -0
- data/test/lib/netutils.rb +42 -0
- data/test/lib/platform_thread.rb +62 -0
- data/test/lib/repoutils.rb +23 -0
- data/test/lib/selenium_extensions.rb +32 -0
- data/test/lib/stubio.rb +37 -0
- data/test/lib/svn_excerpts.rb +288 -0
- data/test/lib/test_configuration.rb +14 -0
- data/test/lib/webserver.rb +71 -0
- data/test/meta/configuration_test.rb +72 -0
- data/test/meta/darcs_repo_test.rb +118 -0
- data/test/meta/local_svn_test.rb +125 -0
- data/test/meta/platform_thread_test.rb +46 -0
- data/test/meta/stubio_test.rb +44 -0
- data/test/mocks/headline.rb +34 -0
- data/test/mocks/svn_reporter.rb +29 -0
- data/test/stubs/svn_settings.rb +19 -0
- data/test/stubs/url_generator.rb +24 -0
- data/test/test_helper.rb +36 -0
- data/test/unit/cache_reporter_fetcher_test.rb +46 -0
- data/test/unit/cache_reporter_test.rb +97 -0
- data/test/unit/caching_test.rb +78 -0
- data/test/unit/change_test.rb +152 -0
- data/test/unit/chdir_runner_test.rb +77 -0
- data/test/unit/chief_editor_test.rb +234 -0
- data/test/unit/darcs_connection_test.rb +109 -0
- data/test/unit/darcs_reporter_test.rb +146 -0
- data/test/unit/darcs_settings_test.rb +37 -0
- data/test/unit/darcs_temp_repo_test.rb +51 -0
- data/test/unit/default_page_provider_test.rb +46 -0
- data/test/unit/diff_table_builder_test.rb +602 -0
- data/test/unit/headline_test.rb +259 -0
- data/test/unit/page_test.rb +145 -0
- data/test/unit/relative_time_test.rb +56 -0
- data/test/unit/reporter_driver_test.rb +85 -0
- data/test/unit/reporter_fetcher_test.rb +31 -0
- data/test/unit/reporter_test.rb +81 -0
- data/test/unit/runner_test.rb +93 -0
- data/test/unit/settings_test.rb +55 -0
- data/test/unit/string_extensions_test.rb +10 -0
- data/test/unit/svn_connection_test.rb +183 -0
- data/test/unit/svn_reporter_interaction_test.rb +38 -0
- data/test/unit/svn_reporter_test.rb +286 -0
- data/test/unit/svn_settings_test.rb +86 -0
- data/test/unit/translator_test.rb +96 -0
- data/test/unit/user_test.rb +125 -0
- data/test/unit/wiki_renderer_test.rb +87 -0
- data/test/unit/wiki_reporter_test.rb +94 -0
- data/test/unit/wiki_url_generator_test.rb +31 -0
- data/vendor/motiro-installer.rb +159 -0
- data/vendor/plugins/globalize/LICENSE +9 -0
- data/vendor/plugins/globalize/README +49 -0
- data/vendor/plugins/globalize/data/country_data.csv +240 -0
- data/vendor/plugins/globalize/data/language_data.csv +188 -0
- data/vendor/plugins/globalize/data/translation_data.csv +3421 -0
- data/vendor/plugins/globalize/generators/globalize/USAGE +10 -0
- data/vendor/plugins/globalize/generators/globalize/globalize_generator.rb +42 -0
- data/vendor/plugins/globalize/generators/globalize/templates/migration.rb.gz +0 -0
- data/vendor/plugins/globalize/generators/globalize/templates/tiny_migration.rb.gz +0 -0
- data/vendor/plugins/globalize/init.rb +30 -0
- data/vendor/plugins/globalize/lib/globalize/localization/core_ext.rb +170 -0
- data/vendor/plugins/globalize/lib/globalize/localization/core_ext_hooks.rb +33 -0
- data/vendor/plugins/globalize/lib/globalize/localization/db_translate.rb +494 -0
- data/vendor/plugins/globalize/lib/globalize/localization/db_view_translator.rb +152 -0
- data/vendor/plugins/globalize/lib/globalize/localization/locale.rb +173 -0
- data/vendor/plugins/globalize/lib/globalize/localization/rfc_3066.rb +40 -0
- data/vendor/plugins/globalize/lib/globalize/models/country.rb +24 -0
- data/vendor/plugins/globalize/lib/globalize/models/currency.rb +188 -0
- data/vendor/plugins/globalize/lib/globalize/models/language.rb +84 -0
- data/vendor/plugins/globalize/lib/globalize/models/model_translation.rb +4 -0
- data/vendor/plugins/globalize/lib/globalize/models/translation.rb +9 -0
- data/vendor/plugins/globalize/lib/globalize/models/view_translation.rb +14 -0
- data/vendor/plugins/globalize/lib/globalize/rails/action_mailer.rb +125 -0
- data/vendor/plugins/globalize/lib/globalize/rails/action_view.rb +79 -0
- data/vendor/plugins/globalize/lib/globalize/rails/active_record.rb +129 -0
- data/vendor/plugins/globalize/lib/globalize/rails/active_record_helper.rb +33 -0
- data/vendor/plugins/globalize/populators/pop_dates.rb +81 -0
- data/vendor/plugins/globalize/populators/pop_migration.rb +18 -0
- data/vendor/plugins/globalize/populators/pop_pluralization.rb +26 -0
- data/vendor/plugins/globalize/populators/pop_seps.rb +32 -0
- data/vendor/plugins/globalize/tasks/data.rake +130 -0
- data/vendor/plugins/globalize/test/action_mailer_test/globalize_mailer/test.en-US.plain.text.rhtml +1 -0
- data/vendor/plugins/globalize/test/action_mailer_test/globalize_mailer/test.en.plain.text.rhtml +1 -0
- data/vendor/plugins/globalize/test/action_mailer_test/globalize_mailer/test.he.plain.text.rhtml +1 -0
- data/vendor/plugins/globalize/test/action_mailer_test/globalize_mailer/test.plain.text.rhtml +1 -0
- data/vendor/plugins/globalize/test/action_mailer_test.rb +54 -0
- data/vendor/plugins/globalize/test/config/database.yml.default +16 -0
- data/vendor/plugins/globalize/test/config/database.yml.example +22 -0
- data/vendor/plugins/globalize/test/core_ext_test.rb +61 -0
- data/vendor/plugins/globalize/test/currency_test.rb +141 -0
- data/vendor/plugins/globalize/test/date_helper_test.rb +634 -0
- data/vendor/plugins/globalize/test/db/schema.rb +90 -0
- data/vendor/plugins/globalize/test/db_translation_test.rb +374 -0
- data/vendor/plugins/globalize/test/fixtures/globalize_categories.yml +7 -0
- data/vendor/plugins/globalize/test/fixtures/globalize_categories_products.yml +7 -0
- data/vendor/plugins/globalize/test/fixtures/globalize_countries.yml +41 -0
- data/vendor/plugins/globalize/test/fixtures/globalize_languages.yml +64 -0
- data/vendor/plugins/globalize/test/fixtures/globalize_manufacturers.yml +5 -0
- data/vendor/plugins/globalize/test/fixtures/globalize_products.yml +29 -0
- data/vendor/plugins/globalize/test/fixtures/globalize_simples.yml +5 -0
- data/vendor/plugins/globalize/test/fixtures/globalize_translations.yml +354 -0
- data/vendor/plugins/globalize/test/locale_test.rb +27 -0
- data/vendor/plugins/globalize/test/mime_responds_test.rb +358 -0
- data/vendor/plugins/globalize/test/model_test.rb +17 -0
- data/vendor/plugins/globalize/test/standard_data_test_helper.rb +33 -0
- data/vendor/plugins/globalize/test/test_helper.rb +19 -0
- data/vendor/plugins/globalize/test/test_standard_data.rb +54 -0
- data/vendor/plugins/globalize/test/validation_test.rb +29 -0
- data/vendor/plugins/globalize/test/view_picking_test.rb +49 -0
- data/vendor/plugins/globalize/test/view_translation_test.rb +237 -0
- data/vendor/plugins/globalize/test/views/layouts/standard.rhtml +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/all_types_with_layout.rhtml +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/all_types_with_layout.rjs +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults.en.rhtml +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults.en.rjs +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults.en.rxml +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults.fr.rhtml +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults.fr.rjs +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults.fr.rxml +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults.rhtml +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults.rjs +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults.rxml +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.en.rhtml +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.en.rjs +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.en.rxml +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.fr.rhtml +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.fr.rjs +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.fr.rxml +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.rhtml +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.rjs +1 -0
- data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.rxml +1 -0
- data/vendor/plugins/globalize/test/views/test.he-IL.rhtml +1 -0
- data/vendor/plugins/globalize/test/views/test.rhtml +1 -0
- data/vendor/plugins/globalize/test/views/test2.he.rhtml +1 -0
- data/vendor/plugins/globalize/test/views/test2.rhtml +1 -0
- data/vendor/plugins/test_xml/MIT-LICENSE +20 -0
- data/vendor/plugins/test_xml/README +20 -0
- data/vendor/plugins/test_xml/Rakefile +22 -0
- data/vendor/plugins/test_xml/init.rb +7 -0
- data/vendor/plugins/test_xml/lib/xml_assertions.rb +22 -0
- data/vendor/plugins/test_xml/test/test_xml_test.rb +40 -0
- metadata +505 -0
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
module Globalize # :nodoc:
|
|
2
|
+
|
|
3
|
+
class WrongLanguageError < ActiveRecord::ActiveRecordError
|
|
4
|
+
attr_reader :original_language, :active_language
|
|
5
|
+
def initialize(orig_lang, active_lang)
|
|
6
|
+
@original_language = orig_lang
|
|
7
|
+
@active_language = active_lang
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class TranslationTrampleError < ActiveRecord::ActiveRecordError; end
|
|
12
|
+
|
|
13
|
+
module DbTranslate # :nodoc:
|
|
14
|
+
|
|
15
|
+
def self.included(base)
|
|
16
|
+
base.extend(ClassMethods)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
module ClassMethods
|
|
20
|
+
=begin rdoc
|
|
21
|
+
Specifies fields that can be translated. These are normal ActiveRecord
|
|
22
|
+
fields, with corresponding database columns, but they are shadowed
|
|
23
|
+
by translations in a special translation table. All the translation
|
|
24
|
+
stuff is done behind the scenes.
|
|
25
|
+
|
|
26
|
+
=== Example:
|
|
27
|
+
|
|
28
|
+
==== In your model:
|
|
29
|
+
class Product < ActiveRecord::Base
|
|
30
|
+
translates :name, :description
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
==== In your controller:
|
|
34
|
+
Locale.set("en_US")
|
|
35
|
+
product.name -> guitar
|
|
36
|
+
|
|
37
|
+
Locale.set("es_ES")
|
|
38
|
+
product.name -> guitarra
|
|
39
|
+
|
|
40
|
+
The standard ActiveRecord +find+ method has been tweaked to work with Globalize.
|
|
41
|
+
Use it in the exact same way you would the regular find, except for the
|
|
42
|
+
following provisos:
|
|
43
|
+
|
|
44
|
+
1. At this point, it will not work with the <tt>:include</tt> option...
|
|
45
|
+
1. However, there is a replacement: <tt>:include_translated</tt>, which will
|
|
46
|
+
be described below.
|
|
47
|
+
1. The <tt>:select</tt> option is prohibited.
|
|
48
|
+
|
|
49
|
+
+find+ returns the retreived models, with all translated fields correctly
|
|
50
|
+
loaded, depending on the active language.
|
|
51
|
+
|
|
52
|
+
<tt>:include_translated</tt> works as follows:
|
|
53
|
+
any model specified in the <tt>:include_translated</tt> option
|
|
54
|
+
will be eagerly loaded and added to the current model as attributes,
|
|
55
|
+
prefixed with the name of the associated model. This is often referred
|
|
56
|
+
to as _piggybacking_.
|
|
57
|
+
|
|
58
|
+
Example:
|
|
59
|
+
class Product < ActiveRecord::Base
|
|
60
|
+
belongs_to :manufacturer
|
|
61
|
+
belongs_to :category
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
class Category < ActiveRecord::Base
|
|
65
|
+
has_many :products
|
|
66
|
+
translates :name
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
prods = Product.find(:all, :include_translated => [ :manufacturer, :category ])
|
|
70
|
+
prods.first.category_name -> "batedeira"
|
|
71
|
+
=end
|
|
72
|
+
def translates(*facets)
|
|
73
|
+
# parse out options hash
|
|
74
|
+
options = facets.pop if facets.last.kind_of? Hash
|
|
75
|
+
options ||= {}
|
|
76
|
+
|
|
77
|
+
facets_string = "[" + facets.map {|facet| ":#{facet}"}.join(", ") + "]"
|
|
78
|
+
class_eval <<-HERE
|
|
79
|
+
@@facet_options = {}
|
|
80
|
+
attr_writer :fully_loaded
|
|
81
|
+
def fully_loaded?; @fully_loaded; end
|
|
82
|
+
@@globalize_facets = #{facets_string}
|
|
83
|
+
@@preload_facets ||= @@globalize_facets
|
|
84
|
+
class << self
|
|
85
|
+
|
|
86
|
+
def sqlite?; connection.kind_of? ActiveRecord::ConnectionAdapters::SQLiteAdapter end
|
|
87
|
+
|
|
88
|
+
def globalize_facets
|
|
89
|
+
@@globalize_facets
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def globalize_facets_hash
|
|
93
|
+
@@globalize_facets_hash ||= globalize_facets.inject({}) {|hash, facet|
|
|
94
|
+
hash[facet.to_s] = true; hash
|
|
95
|
+
}
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def untranslated_fields
|
|
99
|
+
@@untranslated_fields ||=
|
|
100
|
+
column_names.map {|cn| cn.intern } - globalize_facets
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def preload_facets; @@preload_facets; end
|
|
104
|
+
def postload_facets
|
|
105
|
+
@@postload_facets ||= @@globalize_facets - @@preload_facets
|
|
106
|
+
end
|
|
107
|
+
alias_method :globalize_old_find_every, :find_every unless
|
|
108
|
+
respond_to? :globalize_old_find_every
|
|
109
|
+
end
|
|
110
|
+
alias_method :globalize_old_reload, :reload
|
|
111
|
+
alias_method :globalize_old_destroy, :destroy
|
|
112
|
+
alias_method :globalize_old_create_or_update, :create_or_update
|
|
113
|
+
alias_method :globalize_old_update, :update
|
|
114
|
+
|
|
115
|
+
include Globalize::DbTranslate::TranslateObjectMethods
|
|
116
|
+
extend Globalize::DbTranslate::TranslateClassMethods
|
|
117
|
+
|
|
118
|
+
HERE
|
|
119
|
+
|
|
120
|
+
facets.each do |facet|
|
|
121
|
+
bidi = (!(options[facet] && !options[facet][:bidi_embed])).to_s
|
|
122
|
+
class_eval <<-HERE
|
|
123
|
+
@@facet_options[:#{facet}] ||= {}
|
|
124
|
+
@@facet_options[:#{facet}][:bidi] = #{bidi}
|
|
125
|
+
|
|
126
|
+
def #{facet}
|
|
127
|
+
if not_original_language
|
|
128
|
+
raise WrongLanguageError.new(@original_language, Locale.language)
|
|
129
|
+
end
|
|
130
|
+
load_other_translations if
|
|
131
|
+
!fully_loaded? && !self.class.preload_facets.include?(:#{facet})
|
|
132
|
+
result = read_attribute(:#{facet})
|
|
133
|
+
return nil if result.nil?
|
|
134
|
+
result.direction = #{facet}_is_base? ?
|
|
135
|
+
(Locale.base_language ? Locale.base_language.direction : nil) :
|
|
136
|
+
(@original_language ? @original_language.direction : nil)
|
|
137
|
+
|
|
138
|
+
# insert bidi embedding characters, if necessary
|
|
139
|
+
if @@facet_options[:#{facet}][:bidi] &&
|
|
140
|
+
Locale.language && Locale.language.direction && result.direction
|
|
141
|
+
if Locale.language.direction == 'ltr' && result.direction == 'rtl'
|
|
142
|
+
bidi_str = "\xe2\x80\xab" + result + "\xe2\x80\xac"
|
|
143
|
+
bidi_str.direction = result.direction
|
|
144
|
+
return bidi_str
|
|
145
|
+
elsif Locale.language.direction == 'rtl' && result.direction == 'ltr'
|
|
146
|
+
bidi_str = "\xe2\x80\xaa" + result + "\xe2\x80\xac"
|
|
147
|
+
bidi_str.direction = result.direction
|
|
148
|
+
return bidi_str
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
return result
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def #{facet}=(arg)
|
|
156
|
+
raise WrongLanguageError.new(@original_language, Locale.language) if
|
|
157
|
+
not_original_language
|
|
158
|
+
write_attribute(:#{facet}, arg)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def #{facet}_is_base?
|
|
162
|
+
self['#{facet}_not_base'].nil?
|
|
163
|
+
end
|
|
164
|
+
HERE
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
=begin rdoc
|
|
170
|
+
Optionally specifies translated fields to be preloaded on <tt>find</tt>. For instance,
|
|
171
|
+
in a product catalog, you may want to do a <tt>find</tt> of the first 10 products:
|
|
172
|
+
|
|
173
|
+
Product.find(:all, :limit => 10, :order => "name")
|
|
174
|
+
|
|
175
|
+
But you wouldn't want to load the complete descriptions and specs of all the
|
|
176
|
+
products, just the names and summaries. So you'd specify:
|
|
177
|
+
|
|
178
|
+
class Product < ActiveRecord::Base
|
|
179
|
+
translates :name, :summary, :description, :specs
|
|
180
|
+
translates_preload :name, :summary
|
|
181
|
+
...
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
By default (if no translates_preload is specified), Globalize will preload
|
|
185
|
+
the first field given to <tt>translates</tt>. It will also fully load on
|
|
186
|
+
a <tt>find(:first)</tt> or when <tt>:translate_all => true</tt> is given as a find option.
|
|
187
|
+
=end
|
|
188
|
+
def translates_preload(*facets)
|
|
189
|
+
module_eval <<-HERE
|
|
190
|
+
@@preload_facets = facets
|
|
191
|
+
HERE
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
module TranslateObjectMethods # :nodoc: all
|
|
197
|
+
|
|
198
|
+
module_eval <<-HERE
|
|
199
|
+
def not_original_language
|
|
200
|
+
return false if @original_language.nil?
|
|
201
|
+
return @original_language != Locale.language
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def set_original_language
|
|
205
|
+
@original_language = Locale.language
|
|
206
|
+
end
|
|
207
|
+
HERE
|
|
208
|
+
|
|
209
|
+
def load_other_translations
|
|
210
|
+
postload_facets = self.class.postload_facets
|
|
211
|
+
return if postload_facets.empty? || new_record?
|
|
212
|
+
|
|
213
|
+
table_name = self.class.table_name
|
|
214
|
+
facet_selection = postload_facets.join(", ")
|
|
215
|
+
base = connection.select_one("SELECT #{facet_selection} " +
|
|
216
|
+
" FROM #{table_name} WHERE #{self.class.primary_key} = #{id}",
|
|
217
|
+
"loading base for load_other_translations")
|
|
218
|
+
base.each {|key, val| write_attribute( key, val ) }
|
|
219
|
+
|
|
220
|
+
unless Locale.base?
|
|
221
|
+
trs = ModelTranslation.find(:all,
|
|
222
|
+
:conditions => [ "table_name = ? AND item_id = ? AND language_id = ? AND " +
|
|
223
|
+
"facet IN (#{[ '?' ] * postload_facets.size * ', '})", table_name,
|
|
224
|
+
self.id, Locale.active.language.id ] + postload_facets.map {|facet| facet.to_s} )
|
|
225
|
+
trs ||= []
|
|
226
|
+
trs.each do |tr|
|
|
227
|
+
attr = tr.text || base[tr.facet.to_s]
|
|
228
|
+
write_attribute( tr.facet, attr )
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
self.fully_loaded = true
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def destroy
|
|
235
|
+
globalize_old_destroy
|
|
236
|
+
ModelTranslation.delete_all( [ "table_name = ? AND item_id = ?",
|
|
237
|
+
self.class.table_name, id ])
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def reload
|
|
241
|
+
globalize_old_reload
|
|
242
|
+
set_original_language
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
private
|
|
246
|
+
|
|
247
|
+
# Returns copy of the attributes hash where all the values have been safely quoted for use in
|
|
248
|
+
# an SQL statement.
|
|
249
|
+
# REDEFINED to include only untranslated fields. We don't want to overwrite the
|
|
250
|
+
# base translation with other translations.
|
|
251
|
+
def attributes_with_quotes(include_primary_key = true)
|
|
252
|
+
if Locale.base?
|
|
253
|
+
attributes.inject({}) do |quoted, (name, value)|
|
|
254
|
+
if column = column_for_attribute(name)
|
|
255
|
+
quoted[name] = quote(value, column) unless !include_primary_key && column.primary
|
|
256
|
+
end
|
|
257
|
+
quoted
|
|
258
|
+
end
|
|
259
|
+
else
|
|
260
|
+
attributes.inject({}) do |quoted, (name, value)|
|
|
261
|
+
if !self.class.globalize_facets_hash.has_key?(name) &&
|
|
262
|
+
column = column_for_attribute(name)
|
|
263
|
+
quoted[name] = quote(value, column) unless !include_primary_key && column.primary
|
|
264
|
+
end
|
|
265
|
+
quoted
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def create_or_update
|
|
271
|
+
result = globalize_old_create_or_update
|
|
272
|
+
update_translation if Locale.active && result
|
|
273
|
+
result
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def update
|
|
277
|
+
status = true
|
|
278
|
+
status = globalize_old_update unless attributes_with_quotes(false).empty?
|
|
279
|
+
status
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def update_translation
|
|
283
|
+
raise WrongLanguageError.new(@original_language, Locale.language) if
|
|
284
|
+
not_original_language
|
|
285
|
+
|
|
286
|
+
set_original_language
|
|
287
|
+
|
|
288
|
+
# nothing to do, facets updated in main model
|
|
289
|
+
return if Locale.base?
|
|
290
|
+
|
|
291
|
+
table_name = self.class.table_name
|
|
292
|
+
self.class.globalize_facets.each do |facet|
|
|
293
|
+
next unless has_attribute?(facet)
|
|
294
|
+
text = read_attribute(facet)
|
|
295
|
+
language_id = Locale.active.language.id
|
|
296
|
+
tr = ModelTranslation.find(:first, :conditions =>
|
|
297
|
+
[ "table_name = ? AND item_id = ? AND facet = ? AND language_id = ?",
|
|
298
|
+
table_name, id, facet.to_s, language_id ])
|
|
299
|
+
if tr.nil?
|
|
300
|
+
# create new record
|
|
301
|
+
ModelTranslation.create(:table_name => table_name,
|
|
302
|
+
:item_id => id, :facet => facet.to_s,
|
|
303
|
+
:language_id => language_id,
|
|
304
|
+
:text => text) unless text.nil?
|
|
305
|
+
elsif text.blank?
|
|
306
|
+
# delete record
|
|
307
|
+
tr.destroy
|
|
308
|
+
else
|
|
309
|
+
# update record
|
|
310
|
+
tr.update_attribute(:text, text) if tr.text != text
|
|
311
|
+
end
|
|
312
|
+
end # end facets loop
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
module TranslateClassMethods
|
|
318
|
+
|
|
319
|
+
# Use this instead of +find+ if you want to bypass the translation
|
|
320
|
+
# code for any reason.
|
|
321
|
+
def untranslated_find(*args)
|
|
322
|
+
has_options = args.last.is_a?(Hash)
|
|
323
|
+
options = has_options ? args.last : {}
|
|
324
|
+
options[:untranslated] = true
|
|
325
|
+
args << options if !has_options
|
|
326
|
+
find(*args)
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
protected
|
|
330
|
+
# FIX: figure out how to use default rails VALID_FIND_OPTIONS constant
|
|
331
|
+
VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset,
|
|
332
|
+
:order, :select, :readonly, :group, :from,
|
|
333
|
+
:untranslated, :include_translated ]
|
|
334
|
+
|
|
335
|
+
def validate_find_options(options) #:nodoc:
|
|
336
|
+
options.assert_valid_keys(VALID_FIND_OPTIONS)
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
private
|
|
340
|
+
def find_every(options)
|
|
341
|
+
return globalize_old_find_every(options) if options[:untranslated]
|
|
342
|
+
raise StandardError,
|
|
343
|
+
":select option not allowed on translatable models " +
|
|
344
|
+
"(#{options[:select]})" if options[:select] && !options[:select].empty?
|
|
345
|
+
|
|
346
|
+
# do quick version if base language is active
|
|
347
|
+
if Locale.base? && !options.has_key?(:include_translated)
|
|
348
|
+
results = globalize_old_find_every(options)
|
|
349
|
+
results.each {|result|
|
|
350
|
+
result.set_original_language
|
|
351
|
+
}
|
|
352
|
+
return results
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
options[:conditions] = fix_conditions(options[:conditions]) if options[:conditions]
|
|
356
|
+
|
|
357
|
+
# there will at least be an +id+ field here
|
|
358
|
+
select_clause = untranslated_fields.map {|f| "#{table_name}.#{f}" }.join(", ")
|
|
359
|
+
|
|
360
|
+
joins_clause = options[:joins].nil? ? "" : options[:joins].dup
|
|
361
|
+
joins_args = []
|
|
362
|
+
load_full = options[:translate_all]
|
|
363
|
+
facets = load_full ? globalize_facets : preload_facets
|
|
364
|
+
|
|
365
|
+
if Locale.base?
|
|
366
|
+
select_clause << ', ' << facets.map {|f| "#{table_name}.#{f}" }.join(", ")
|
|
367
|
+
else
|
|
368
|
+
language_id = Locale.active.language.id
|
|
369
|
+
load_full = options[:translate_all]
|
|
370
|
+
facets = load_full ? globalize_facets : preload_facets
|
|
371
|
+
|
|
372
|
+
=begin
|
|
373
|
+
There's a bug in sqlite that messes up sorting when aliasing fields,
|
|
374
|
+
see: <http://www.sqlite.org/cvstrac/tktview?tn=1521,33>.
|
|
375
|
+
|
|
376
|
+
Since I want to use sqlite, and sorting, I'm hacking this to make it work.
|
|
377
|
+
This involves renaming order by fields and adding them to the SELECT part.
|
|
378
|
+
It's a sucky hack, but hopefully sqlite will fix the bug soon.
|
|
379
|
+
=end
|
|
380
|
+
|
|
381
|
+
# sqlite bug hack
|
|
382
|
+
select_position = untranslated_fields.size
|
|
383
|
+
|
|
384
|
+
# initialize where tweaking
|
|
385
|
+
if options[:conditions].nil?
|
|
386
|
+
where_clause = ""
|
|
387
|
+
else
|
|
388
|
+
if options[:conditions].kind_of? Array
|
|
389
|
+
conditions_is_array = true
|
|
390
|
+
where_clause = options[:conditions].shift
|
|
391
|
+
else
|
|
392
|
+
where_clause = options[:conditions]
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
facets.each do |facet|
|
|
397
|
+
facet = facet.to_s
|
|
398
|
+
facet_table_alias = "t_#{facet}"
|
|
399
|
+
|
|
400
|
+
# sqlite bug hack
|
|
401
|
+
select_position += 1
|
|
402
|
+
options[:order].sub!(/\b#{facet}\b/, select_position.to_s) if options[:order] && sqlite?
|
|
403
|
+
|
|
404
|
+
select_clause << ", COALESCE(#{facet_table_alias}.text, #{table_name}.#{facet}) AS #{facet}, "
|
|
405
|
+
select_clause << " #{facet_table_alias}.text AS #{facet}_not_base "
|
|
406
|
+
joins_clause << " LEFT OUTER JOIN globalize_translations AS #{facet_table_alias} " +
|
|
407
|
+
"ON #{facet_table_alias}.table_name = ? " +
|
|
408
|
+
"AND #{table_name}.#{primary_key} = #{facet_table_alias}.item_id " +
|
|
409
|
+
"AND #{facet_table_alias}.facet = ? AND #{facet_table_alias}.language_id = ? "
|
|
410
|
+
joins_args << table_name << facet << language_id
|
|
411
|
+
|
|
412
|
+
#for translated fields inside WHERE clause substitute corresponding COALESCE string
|
|
413
|
+
where_clause.gsub!(/((((#{table_name}\.)|\W)#{facet})|^#{facet})\W/, " COALESCE(#{facet_table_alias}.text, #{table_name}.#{facet}) ")
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
options[:conditions] = sanitize_sql(
|
|
417
|
+
conditions_is_array ? [ where_clause ] + options[:conditions] : where_clause
|
|
418
|
+
) unless options[:conditions].nil?
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
# add in associations (of :belongs_to nature) if applicable
|
|
422
|
+
associations = options[:include_translated] || []
|
|
423
|
+
associations = [ associations ].flatten
|
|
424
|
+
associations.each do |assoc|
|
|
425
|
+
rfxn = reflect_on_association(assoc)
|
|
426
|
+
assoc_type = rfxn.macro
|
|
427
|
+
raise StandardError,
|
|
428
|
+
":include_translated associations must be of type :belongs_to;" +
|
|
429
|
+
"#{assoc} is #{assoc_type}" if assoc_type != :belongs_to
|
|
430
|
+
klass = rfxn.klass
|
|
431
|
+
assoc_facets = klass.preload_facets
|
|
432
|
+
included_table = klass.table_name
|
|
433
|
+
included_fk = klass.primary_key
|
|
434
|
+
fk = rfxn.options[:foreign_key] || "#{assoc}_id"
|
|
435
|
+
assoc_facets.each do |facet|
|
|
436
|
+
facet_table_alias = "t_#{assoc}_#{facet}"
|
|
437
|
+
|
|
438
|
+
if Locale.base?
|
|
439
|
+
select_clause << ", #{included_table}.#{facet} AS #{assoc}_#{facet} "
|
|
440
|
+
else
|
|
441
|
+
select_clause << ", COALESCE(#{facet_table_alias}.text, #{included_table}.#{facet}) " +
|
|
442
|
+
"AS #{assoc}_#{facet} "
|
|
443
|
+
joins_clause << " LEFT OUTER JOIN globalize_translations AS #{facet_table_alias} " +
|
|
444
|
+
"ON #{facet_table_alias}.table_name = ? " +
|
|
445
|
+
"AND #{table_name}.#{fk} = #{facet_table_alias}.item_id " +
|
|
446
|
+
"AND #{facet_table_alias}.facet = ? AND #{facet_table_alias}.language_id = ? "
|
|
447
|
+
joins_args << klass.table_name << facet.to_s << language_id
|
|
448
|
+
end
|
|
449
|
+
end
|
|
450
|
+
joins_clause << "LEFT OUTER JOIN #{included_table} " +
|
|
451
|
+
"ON #{table_name}.#{fk} = #{included_table}.#{included_fk} "
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
options[:select] = select_clause
|
|
455
|
+
options[:readonly] = false
|
|
456
|
+
|
|
457
|
+
sanitized_joins_clause = sanitize_sql( [ joins_clause, *joins_args ] )
|
|
458
|
+
options[:joins] = sanitized_joins_clause
|
|
459
|
+
results = globalize_old_find_every(options)
|
|
460
|
+
|
|
461
|
+
results.each {|result|
|
|
462
|
+
result.set_original_language
|
|
463
|
+
result.fully_loaded = true if load_full
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return results
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
# properly scope conditions to table
|
|
470
|
+
def fix_conditions(conditions)
|
|
471
|
+
if conditions.kind_of? Array
|
|
472
|
+
is_array = true
|
|
473
|
+
sql = conditions.shift
|
|
474
|
+
else
|
|
475
|
+
is_array = false
|
|
476
|
+
sql = conditions
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
column_names.each do |column_name|
|
|
480
|
+
sql.gsub!( /(^|([^\.\w"'`]+))(["'`]?)#{column_name}(?!\w)/,
|
|
481
|
+
'\1' + "#{table_name}." + '\3' + "#{column_name}" )
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
if is_array
|
|
485
|
+
[ sql ] + conditions
|
|
486
|
+
else
|
|
487
|
+
sql
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
module Globalize # :nodoc:
|
|
2
|
+
class DbViewTranslator
|
|
3
|
+
include Singleton
|
|
4
|
+
|
|
5
|
+
# The maximum size of the cache in kilobytes.
|
|
6
|
+
# This is just a rough estimate, the cache can grow bigger than this figure.
|
|
7
|
+
attr_accessor :max_cache_size
|
|
8
|
+
|
|
9
|
+
attr_reader :cache_size, :cache_total_hits, :cache_total_queries
|
|
10
|
+
|
|
11
|
+
def fetch(key, language, default = nil, arg = nil) # :nodoc:
|
|
12
|
+
|
|
13
|
+
# use argument as pluralization number, if number
|
|
14
|
+
num = arg.kind_of?(Numeric) ? arg : nil
|
|
15
|
+
|
|
16
|
+
# if there's no translation, use default or original key
|
|
17
|
+
real_default = default || key
|
|
18
|
+
|
|
19
|
+
result = fetch_from_cache(key, language, real_default, num)
|
|
20
|
+
|
|
21
|
+
if num
|
|
22
|
+
return result.sub('%d', num.to_s)
|
|
23
|
+
else
|
|
24
|
+
return arg.nil? ? result : result.sub('%s', arg.to_s)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def set(key, language, translations, zero_form = nil) # :nodoc:
|
|
29
|
+
raise ArgumentError, "No language set" if !language
|
|
30
|
+
if translations.kind_of? Array
|
|
31
|
+
translations = [ zero_form ] + translations
|
|
32
|
+
else
|
|
33
|
+
translations = [ zero_form, translations ]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
idx = 0
|
|
37
|
+
translations.each do |translation|
|
|
38
|
+
set_pluralized(key, language, idx, translation)
|
|
39
|
+
idx += 1
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def set_pluralized(key, language, idx, translation)
|
|
44
|
+
invalidate_cache(key, language, idx)
|
|
45
|
+
ViewTranslation.transaction do
|
|
46
|
+
old_tr = ViewTranslation.pick(key, language, idx)
|
|
47
|
+
if old_tr
|
|
48
|
+
old_tr.update_attribute(:text, translation)
|
|
49
|
+
else
|
|
50
|
+
ViewTranslation.create!(:tr_key => key,
|
|
51
|
+
:language_id => language.id, :pluralization_index => idx,
|
|
52
|
+
:text => translation)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Returns the number of items in the cache.
|
|
58
|
+
def cache_count
|
|
59
|
+
@cache.size
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Resets the cache and its statistics -- for testing.
|
|
63
|
+
def cache_reset
|
|
64
|
+
cache_clear
|
|
65
|
+
@cache_total_hits = 0
|
|
66
|
+
@cache_total_queries = 0
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
def fetch_view_translation(key, language, idx)
|
|
71
|
+
tr = nil
|
|
72
|
+
ViewTranslation.transaction do
|
|
73
|
+
tr = ViewTranslation.pick(key, language, idx)
|
|
74
|
+
|
|
75
|
+
# fill in a nil record for missed translations report
|
|
76
|
+
# do not report missing zero-forms -- they're optional
|
|
77
|
+
if !tr && idx != 0
|
|
78
|
+
tr = ViewTranslation.create!(:tr_key => key,
|
|
79
|
+
:language_id => language.id, :pluralization_index => idx,
|
|
80
|
+
:text => nil)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
tr ? tr.text : nil
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def cache_fetch(key, language, idx)
|
|
88
|
+
@cache_total_queries += 1
|
|
89
|
+
cache_key = cache_key(key, language, idx)
|
|
90
|
+
@cache_total_hits += 1 if @cache.has_key?(cache_key)
|
|
91
|
+
@cache[cache_key]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def cache_add(key, language, idx, translation)
|
|
95
|
+
cache_clear if @cache_size > max_cache_size * 1024
|
|
96
|
+
size = key.size + (translation.nil? ? 0 : translation.size)
|
|
97
|
+
@cache_size += size
|
|
98
|
+
@cache[cache_key(key, language, idx)] = translation
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def invalidate_cache(key, language, idx)
|
|
102
|
+
tr = @cache.delete(cache_key(key, language, idx))
|
|
103
|
+
size = key.size + (tr.nil? ? 0 : tr.size)
|
|
104
|
+
@cache_size -= size
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def cache_key(key, language, idx)
|
|
108
|
+
[ key, language.code, idx ].join(':')
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def cache_hit_ratio
|
|
112
|
+
@cache_total_hits / @cache_total_queries
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def cache_clear
|
|
116
|
+
@cache.clear
|
|
117
|
+
@cache_size = 0
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def initialize
|
|
121
|
+
@cache = {}
|
|
122
|
+
@cache_size = 0
|
|
123
|
+
@cache_total_hits = 0
|
|
124
|
+
@cache_total_queries = 0
|
|
125
|
+
|
|
126
|
+
# default cache size is 8mb
|
|
127
|
+
@max_cache_size = 8192
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def fetch_from_cache(key, language, real_default, num)
|
|
131
|
+
return real_default if language.nil?
|
|
132
|
+
|
|
133
|
+
zero_form = num == 0
|
|
134
|
+
plural_idx = language.plural_index(num) # language-defined plural form
|
|
135
|
+
zplural_idx = zero_form ? 0 : plural_idx # takes zero-form into account
|
|
136
|
+
|
|
137
|
+
cached = cache_fetch(key, language, zplural_idx)
|
|
138
|
+
if cached
|
|
139
|
+
result = cached
|
|
140
|
+
else
|
|
141
|
+
result = fetch_view_translation(key, language, zplural_idx)
|
|
142
|
+
|
|
143
|
+
# set to plural_form if no zero-form exists
|
|
144
|
+
result ||= fetch_view_translation(key, language, plural_idx) if zero_form
|
|
145
|
+
|
|
146
|
+
cache_add(key, language, zplural_idx, result)
|
|
147
|
+
end
|
|
148
|
+
result ||= real_default
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
end
|
|
152
|
+
end
|