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,173 @@
|
|
|
1
|
+
module Globalize
|
|
2
|
+
|
|
3
|
+
class NoBaseLanguageError < StandardError; end
|
|
4
|
+
|
|
5
|
+
=begin rdoc
|
|
6
|
+
Locale defines the currenctly active _locale_. You'll mostly use it like this:
|
|
7
|
+
Locale.set("en-US")
|
|
8
|
+
|
|
9
|
+
+en+ is the code for English, and +US+ is the country code. The country code is
|
|
10
|
+
optional, but you'll need to define it to get a lot of the localization features.
|
|
11
|
+
=end
|
|
12
|
+
class Locale
|
|
13
|
+
attr_reader :language, :country, :code
|
|
14
|
+
attr_accessor :date_format, :currency_format, :currency_code,
|
|
15
|
+
:thousands_sep, :decimal_sep, :currency_decimal_sep,
|
|
16
|
+
:number_grouping_scheme
|
|
17
|
+
|
|
18
|
+
@@cache = {}
|
|
19
|
+
@@translator_class = DbViewTranslator
|
|
20
|
+
@@translator = {}
|
|
21
|
+
@@active = nil
|
|
22
|
+
@@base_language = nil
|
|
23
|
+
@@base_language_code = nil
|
|
24
|
+
@@translator = @@translator_class.instance
|
|
25
|
+
|
|
26
|
+
# Is there an active locale?
|
|
27
|
+
def self.active?; !@@active.nil? end
|
|
28
|
+
|
|
29
|
+
# This is the focal point of the class. Sets the locale in the familiar
|
|
30
|
+
# RFC 3066 format (see: http://www.faqs.org/rfcs/rfc3066.html). It can
|
|
31
|
+
# also take a Locale object. Set it to the +nil+ object, to deactivate
|
|
32
|
+
# the locale.
|
|
33
|
+
def self.set(locale)
|
|
34
|
+
if locale.kind_of? Locale
|
|
35
|
+
@@active = locale
|
|
36
|
+
elsif locale.nil?
|
|
37
|
+
@@active = nil
|
|
38
|
+
else
|
|
39
|
+
@@active = ( @@cache[locale] ||= Locale.new(locale) )
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Clears the locale cache -- used mostly for testing.
|
|
44
|
+
def self.clear_cache
|
|
45
|
+
@@cache.clear
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Returns the active locale.
|
|
49
|
+
def self.active; @@active end
|
|
50
|
+
|
|
51
|
+
# Sets the base language. The base language is the language that has
|
|
52
|
+
# complete coverage in the database. For instance, if you have a +Category+
|
|
53
|
+
# model with a +name+ field, the base language is the language in which names
|
|
54
|
+
# are stored in the model itself, and not in the translations table.
|
|
55
|
+
#
|
|
56
|
+
# Takes either a language code (valid RFC 3066 code like +en+ or <tt>en-US</tt>)
|
|
57
|
+
# or a language object.
|
|
58
|
+
#
|
|
59
|
+
# May be set with a language code in environment.rb, without accessing the db.
|
|
60
|
+
def self.set_base_language(lang)
|
|
61
|
+
if lang.kind_of? Language
|
|
62
|
+
@@base_language = lang
|
|
63
|
+
else
|
|
64
|
+
@@base_language_code = RFC_3066.parse lang
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Returns the base language. Raises an exception if none is set.
|
|
69
|
+
def self.base_language
|
|
70
|
+
@@base_language ? @@base_language :
|
|
71
|
+
(@@base_language_code ?
|
|
72
|
+
(@@base_language = Language.pick(@@base_language_code)) :
|
|
73
|
+
raise(NoBaseLanguageError, "base language must be defined"))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Is the currently active language the base language?
|
|
77
|
+
def self.base?
|
|
78
|
+
active ? active.language == base_language : true
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Returns the currently active language model or +nil+.
|
|
82
|
+
def self.language
|
|
83
|
+
active? ? active.language : nil
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Returns the currently active language code or +nil+.
|
|
87
|
+
def self.language_code
|
|
88
|
+
active? ? language.code : nil
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Returns the currently active country model or +nil+.
|
|
92
|
+
def self.country
|
|
93
|
+
active? ? active.country : nil
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Creates a new locale object by looking up an RFC 3066 code in the database.
|
|
97
|
+
def initialize(code)
|
|
98
|
+
if code.nil?
|
|
99
|
+
return
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
rfc = RFC_3066.parse(code)
|
|
103
|
+
@code = rfc.locale
|
|
104
|
+
|
|
105
|
+
@language = Language.pick(rfc)
|
|
106
|
+
@country = Country.pick(rfc)
|
|
107
|
+
|
|
108
|
+
setup_fields
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Sets the translation for +key+.
|
|
112
|
+
#
|
|
113
|
+
# :call-seq:
|
|
114
|
+
# Locale.set_translation(key, language, *translations)
|
|
115
|
+
# Locale.set_translation(key, *translations)
|
|
116
|
+
#
|
|
117
|
+
# If +language+ is given, define a translation using that language
|
|
118
|
+
# model, otherwise use the active language.
|
|
119
|
+
#
|
|
120
|
+
# Multiple translation strings may be given, in order to define plural forms.
|
|
121
|
+
# In English, there are only two plural forms, singular and plural, so you
|
|
122
|
+
# would provide two strings at the most. The order is determined by the
|
|
123
|
+
# formula in the languages database. For English, the order is: singular form,
|
|
124
|
+
# then plural.
|
|
125
|
+
#
|
|
126
|
+
# Example:
|
|
127
|
+
# Locale.set_translation("There are %d items in your cart",
|
|
128
|
+
# "There is one item in your cart", "There are %d items in your cart")
|
|
129
|
+
def self.set_translation(key, *options)
|
|
130
|
+
key = key.to_s.gsub('_', ' ') if key.kind_of? Symbol
|
|
131
|
+
if options.first.kind_of? Language
|
|
132
|
+
language = options.shift
|
|
133
|
+
else
|
|
134
|
+
language = self.language
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
raise ArgumentError, "No translations given" if options.empty?
|
|
138
|
+
translator.set(key, language, *options)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def self.set_pluralized_translation(key, *options)
|
|
142
|
+
key = key.to_s.gsub('_', ' ') if key.kind_of? Symbol
|
|
143
|
+
if options.first.kind_of? Language
|
|
144
|
+
language = options.shift
|
|
145
|
+
else
|
|
146
|
+
language = self.language
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
raise ArgumentError, "No translations given" if options.empty?
|
|
150
|
+
translator.set_pluralized(key, language, *options)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def self.translate(key, default = nil, arg = nil) # :nodoc:
|
|
154
|
+
key = key.to_s.gsub('_', ' ') if key.kind_of? Symbol
|
|
155
|
+
|
|
156
|
+
translator.fetch(key, self.language, default, arg)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Returns the translator object -- mostly for testing and adjusting the cache.
|
|
160
|
+
def self.translator; @@translator end
|
|
161
|
+
|
|
162
|
+
private
|
|
163
|
+
|
|
164
|
+
def setup_fields
|
|
165
|
+
return if !@country
|
|
166
|
+
|
|
167
|
+
[:date_format, :currency_format, :currency_code, :thousands_sep,
|
|
168
|
+
:decimal_sep, :currency_decimal_sep, :number_grouping_scheme
|
|
169
|
+
].each {|f| instance_variable_set "@#{f}", @country.send(f) }
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Globalize
|
|
2
|
+
class RFC_3066 # :nodoc:
|
|
3
|
+
attr_accessor :country, :language, :locale
|
|
4
|
+
def self.parse(locale)
|
|
5
|
+
# check for validity
|
|
6
|
+
raise ArgumentError, "bad format for #{locale}, not rfc-3066 compliant" if
|
|
7
|
+
locale !~ /^[a-zA-Z0-9\-]+$/
|
|
8
|
+
|
|
9
|
+
# split/assign
|
|
10
|
+
lang, country, remain = locale.split('-', 3)
|
|
11
|
+
raise ArgumentError, "bad format for #{locale}, not rfc-3066 compliant" if
|
|
12
|
+
lang !~ /^[a-zA-Z]{1,8}$/
|
|
13
|
+
new_language = lang if lang.size == 2 || lang.size == 3
|
|
14
|
+
raise ArgumentError, "bad format for #{locale}, not rfc-3066 compliant" if
|
|
15
|
+
!new_language && lang != 'i' && lang != 'x'
|
|
16
|
+
|
|
17
|
+
raise ArgumentError, "bad format for #{locale}, not rfc-3066 compliant" if
|
|
18
|
+
country && (country.size < 2 || country.size > 8)
|
|
19
|
+
new_country = country if country && country.size == 2
|
|
20
|
+
|
|
21
|
+
rfc = self.new
|
|
22
|
+
rfc.country = new_country
|
|
23
|
+
rfc.language = new_language
|
|
24
|
+
rfc.locale = locale
|
|
25
|
+
|
|
26
|
+
return rfc
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.valid?(locale)
|
|
30
|
+
begin
|
|
31
|
+
parse(locale)
|
|
32
|
+
rescue ArgumentError
|
|
33
|
+
return false
|
|
34
|
+
else
|
|
35
|
+
return true
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Globalize
|
|
2
|
+
class Country < ActiveRecord::Base # :nodoc:
|
|
3
|
+
set_table_name "globalize_countries"
|
|
4
|
+
|
|
5
|
+
def self.reloadable?; false end
|
|
6
|
+
|
|
7
|
+
def self.pick(rfc)
|
|
8
|
+
|
|
9
|
+
# assume it's a country code string
|
|
10
|
+
if rfc.kind_of?(String)
|
|
11
|
+
find_by_code(rfc)
|
|
12
|
+
elsif rfc.kind_of?(RFC_3066)
|
|
13
|
+
rfc.country ? find_by_code(rfc.country) : nil
|
|
14
|
+
else
|
|
15
|
+
raise ArgumentError, "argument must be String or RFC_3066 object"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def number_grouping_scheme
|
|
20
|
+
attr = read_attribute(:number_grouping_scheme)
|
|
21
|
+
attr ? attr.intern : nil
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
module Globalize
|
|
2
|
+
|
|
3
|
+
=begin rdoc
|
|
4
|
+
This is what you use for representing money in your ActiveRecord models.
|
|
5
|
+
It stores values as integers internally and in the database, to safeguard
|
|
6
|
+
precision and rounding.
|
|
7
|
+
|
|
8
|
+
More importantly for globalization freaks, it prints out the amount correctly
|
|
9
|
+
in the current locale, via the handy #format method. Try it!
|
|
10
|
+
|
|
11
|
+
Example:
|
|
12
|
+
|
|
13
|
+
class Product < ActiveRecord::Base
|
|
14
|
+
composed_of :price, :class_name => "Globalize::Currency",
|
|
15
|
+
:mapping => [ %w(price cents) ]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
product.price -> "SFr. 483'232.43"
|
|
19
|
+
=end
|
|
20
|
+
class Currency
|
|
21
|
+
include Comparable
|
|
22
|
+
|
|
23
|
+
attr_reader :cents
|
|
24
|
+
|
|
25
|
+
class CurrencyError < StandardError# :nodoc:
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Creates a new Currency object, given cents. This is used to tie into
|
|
29
|
+
# the ActiveRecord aggregation stuff.
|
|
30
|
+
def initialize(cents)
|
|
31
|
+
@cents = cents.nil? ? nil : cents.to_i
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
@@no_cents = false
|
|
35
|
+
def self.no_cents; @@no_cents end
|
|
36
|
+
def self.no_cents=(val); @@no_cents = val end
|
|
37
|
+
|
|
38
|
+
@@free = Currency.new(0)
|
|
39
|
+
@@free.freeze
|
|
40
|
+
|
|
41
|
+
# Returns the Currency object representing a price of 0.
|
|
42
|
+
def self.free
|
|
43
|
+
@@free
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
@@na = Currency.new(nil)
|
|
47
|
+
@@na.freeze
|
|
48
|
+
|
|
49
|
+
# Returns the Currency object representing an unknown price.
|
|
50
|
+
def self.na
|
|
51
|
+
@@na
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def <=>(other)
|
|
55
|
+
if other.respond_to? :cents
|
|
56
|
+
if na?
|
|
57
|
+
other.na? ? 0 : 1
|
|
58
|
+
else
|
|
59
|
+
other.na? ? -1 : cents <=> other.cents
|
|
60
|
+
end
|
|
61
|
+
elsif other.kind_of? Integer
|
|
62
|
+
na? ? 1 : cents <=> other
|
|
63
|
+
else
|
|
64
|
+
raise "can only compare with money or integer"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def +(other_money)
|
|
69
|
+
raise TypeError, "parameter to Currency#+ must be Currency object" unless
|
|
70
|
+
other_money.kind_of? Currency
|
|
71
|
+
(na? || other_money.na?) ? Currency.na :
|
|
72
|
+
Currency.new(cents + other_money.cents)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def -(other_money)
|
|
76
|
+
raise TypeError, "parameter to Currency#+ must be Currency object" unless
|
|
77
|
+
other_money.kind_of? Currency
|
|
78
|
+
(na? || other_money.na?) ? Currency.na :
|
|
79
|
+
Currency.new(cents - other_money.cents)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Multiply money by amount
|
|
83
|
+
def *(amount)
|
|
84
|
+
return Currency.new(nil) if na?
|
|
85
|
+
new_cents = amount * cents;
|
|
86
|
+
new_cents = new_cents.round if new_cents.respond_to? :round
|
|
87
|
+
Currency.new(new_cents)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Divide money by amount
|
|
91
|
+
def /(amount)
|
|
92
|
+
return Currency.new(nil) if na?
|
|
93
|
+
new_cents = cents / amount;
|
|
94
|
+
new_cents = new_cents.round if new_cents.respond_to? :round
|
|
95
|
+
Currency.new(new_cents)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Returns the formatted version of the amount in local currency.
|
|
99
|
+
# If <tt>:code => true</tt> is specified, format using international
|
|
100
|
+
# 3-letter currency code. If <tt>:country</tt> is specified as well,
|
|
101
|
+
# use that country's currency code for formatting.
|
|
102
|
+
def format(options = {})
|
|
103
|
+
return :no_price_available.t("call for price") if na?
|
|
104
|
+
|
|
105
|
+
force_cents = options[:force_cents]
|
|
106
|
+
if options[:code]
|
|
107
|
+
currency_code = options[:country] ?
|
|
108
|
+
options[:country].currency_code :
|
|
109
|
+
( Locale.active? ? Locale.active.currency_code : nil )
|
|
110
|
+
currency_code ?
|
|
111
|
+
self.amount(false, force_cents) + " " + currency_code :
|
|
112
|
+
self.amount(false, force_cents)
|
|
113
|
+
else
|
|
114
|
+
if Locale.active?
|
|
115
|
+
fmt = Locale.active.currency_format || '$%n'
|
|
116
|
+
fmt.sub('%n', self.amount(false, force_cents))
|
|
117
|
+
else
|
|
118
|
+
self.amount false, force_cents
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Returns the formatted version of the amount, but without the currency symbol.
|
|
124
|
+
# If +unlocalized+ is true, do not format the number according to the current locale,
|
|
125
|
+
# so <tt>Currency.new(1234567) -> 12345.67</tt>. This is useful for sending the
|
|
126
|
+
# amount to payment gateways.
|
|
127
|
+
def amount(unlocalized = false, force_cents = false)
|
|
128
|
+
return nil if na?
|
|
129
|
+
decimal_sep = unlocalized ?
|
|
130
|
+
'.' :
|
|
131
|
+
(Locale.active? ?
|
|
132
|
+
(Locale.active.currency_decimal_sep || Locale.active.decimal_sep || '.') :
|
|
133
|
+
'.')
|
|
134
|
+
dollar_str = unlocalized ? dollar_part.to_s : dollar_part.localize
|
|
135
|
+
result = dollar_str
|
|
136
|
+
result << decimal_sep + sprintf("%02d", cent_part) unless
|
|
137
|
+
self.class.no_cents && !force_cents
|
|
138
|
+
return result
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Same as #format with no arguments.
|
|
142
|
+
def to_s
|
|
143
|
+
self.format
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Parse a string or number into a currency object. Easier to use than #new.
|
|
147
|
+
def self.parse(num)
|
|
148
|
+
case
|
|
149
|
+
when num.is_a?(String)
|
|
150
|
+
raise ArgumentError, "Not an amount (#{num})" if num.delete("^0-9").empty?
|
|
151
|
+
_dollars, _cents = num.delete("^0-9.").split('.', 2)
|
|
152
|
+
_cents = _cents ? _cents[0,2] : 0
|
|
153
|
+
Currency.new(_dollars.to_i * 100 + _cents.to_i)
|
|
154
|
+
when num.is_a?(Numeric)
|
|
155
|
+
Currency.new(num * 100)
|
|
156
|
+
when num.is_a?(NilClass)
|
|
157
|
+
Currency.na
|
|
158
|
+
else
|
|
159
|
+
raise ArgumentError, "Unrecognized object #{num.class.name} for Currency"
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Conversion to self
|
|
164
|
+
def to_currency
|
|
165
|
+
self
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Is the value 0? Is it free?
|
|
169
|
+
def empty?
|
|
170
|
+
cents == 0
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Is the value unknown?
|
|
174
|
+
def na?
|
|
175
|
+
cents.nil?
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
private
|
|
179
|
+
def dollar_part
|
|
180
|
+
na? ? nil : cents / 100
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def cent_part
|
|
184
|
+
na? ? nil : cents % 100
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
end
|
|
188
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
module Globalize
|
|
2
|
+
class Language < ActiveRecord::Base # :nodoc:
|
|
3
|
+
set_table_name "globalize_languages"
|
|
4
|
+
|
|
5
|
+
validates_presence_of :english_name
|
|
6
|
+
|
|
7
|
+
validates_uniqueness_of :iso_639_1, :if => :iso_639_1
|
|
8
|
+
validates_uniqueness_of :iso_639_2, :if => :iso_639_2
|
|
9
|
+
validates_uniqueness_of :iso_639_3, :if => :iso_639_3
|
|
10
|
+
validates_uniqueness_of :rfc_3066, :if => :rfc_3066
|
|
11
|
+
|
|
12
|
+
validates_length_of :pluralization, :maximum => 200, :if => :pluralization
|
|
13
|
+
validates_format_of :pluralization, :with => /^[c=\d?:%!<>&|() ]+$/, :if => :pluralization,
|
|
14
|
+
:message => " has invalid characters. Allowed characters are: " +
|
|
15
|
+
"'c', '=', 0-9, '?', ':', '%', '!', '<', '>', '&', '|', '(', ')', ' '."
|
|
16
|
+
|
|
17
|
+
def self.reloadable?; false end
|
|
18
|
+
|
|
19
|
+
def after_initialize
|
|
20
|
+
if !pluralization.nil? && pluralization.size > 200
|
|
21
|
+
raise SecurityError, "Pluralization field for #{self.english_name} language " +
|
|
22
|
+
"contains potentially harmful code. " +
|
|
23
|
+
"Must be less than 200 characters in length. Was #{pluralization.size} characters."
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
if !pluralization.nil? && pluralization !~ /^[c=\d?:%!<>&|() ]+$/
|
|
27
|
+
raise SecurityError, "Pluralization field ('#{pluralization}') for #{self.english_name} language " +
|
|
28
|
+
"contains potentially harmful code. " +
|
|
29
|
+
"Must only use the characters: 'c', '=', 0-9, '?', ':', " +
|
|
30
|
+
"'%', '!', '<', '>', '&', '|', '(', ')', ' '."
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.pick(rfc)
|
|
35
|
+
if rfc.kind_of? String then rfc = RFC_3066.parse(rfc) end
|
|
36
|
+
if rfc.locale.include? '-'
|
|
37
|
+
lang = find_by_rfc_3066(rfc.locale)
|
|
38
|
+
return lang if lang
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
code = rfc.language
|
|
42
|
+
if code.size == 2
|
|
43
|
+
lang = find_by_iso_639_1(code)
|
|
44
|
+
elsif code.size == 3
|
|
45
|
+
lang = find_by_iso_639_3(code)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
lang
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def code; iso_639_1 || iso_639_3 || rfc_3066; end
|
|
52
|
+
|
|
53
|
+
def code=(new_code)
|
|
54
|
+
if new_code =~ /-/
|
|
55
|
+
self.rfc_3066 = new_code
|
|
56
|
+
else
|
|
57
|
+
raise ArgumentError,
|
|
58
|
+
"code must be in rfc_3066 format, with a hyphen character; was #{new_code}"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def native_name; self['native_name'] || self['english_name'] end
|
|
63
|
+
|
|
64
|
+
def ==(other)
|
|
65
|
+
return false if !other.kind_of? Language
|
|
66
|
+
self.code == other.code
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def plural_index(num)
|
|
70
|
+
|
|
71
|
+
# number is not defined, so we assume no pluralization
|
|
72
|
+
return 1 if num.nil?
|
|
73
|
+
|
|
74
|
+
c = num
|
|
75
|
+
expr = pluralization || 'c == 1 ? 2 : 1'
|
|
76
|
+
|
|
77
|
+
instance_eval(expr)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def to_s; english_name end
|
|
81
|
+
def inspect; english_name end
|
|
82
|
+
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Globalize
|
|
2
|
+
# Represents a view translation in the DB, which is a translation of a string
|
|
3
|
+
# in the rails application itself. This includes error messages, controllers,
|
|
4
|
+
# views, and flashes, but not database content.
|
|
5
|
+
class ViewTranslation < Translation # :nodoc:
|
|
6
|
+
|
|
7
|
+
def self.pick(key, language, idx)
|
|
8
|
+
find(:first, :conditions => [
|
|
9
|
+
'tr_key = ? AND language_id = ? AND pluralization_index = ?',
|
|
10
|
+
key, language.id, idx ])
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Search for translated templates or fall back to the default one
|
|
2
|
+
module ActionMailer # :nodoc:
|
|
3
|
+
|
|
4
|
+
# Globalize overrides the create! method to support multiple templates
|
|
5
|
+
# for different locales. For example, for English it will select the template:
|
|
6
|
+
# signup_notification.en-US.text.html.rhtml
|
|
7
|
+
#
|
|
8
|
+
# It will look for the currently active locale code (en-US) first,
|
|
9
|
+
# then the language code (en).
|
|
10
|
+
#
|
|
11
|
+
# If neither of those are found, it will use the regular name:
|
|
12
|
+
# signup_notification.text.html.rhtml
|
|
13
|
+
#
|
|
14
|
+
# It is fully backwards compatible with the original Rails version.
|
|
15
|
+
class Base
|
|
16
|
+
|
|
17
|
+
# Initialize the mailer via the given +method_name+. The body will be
|
|
18
|
+
# rendered and a new TMail::Mail object created.
|
|
19
|
+
#
|
|
20
|
+
# This method is overriden by Globalize to support multiple templates
|
|
21
|
+
# for different locales. For example, use:
|
|
22
|
+
# signup_notification.en-US.text.html.rhtml
|
|
23
|
+
# It is fully backwards compatible with the original rails version.
|
|
24
|
+
def create!(method_name, *parameters) #:nodoc:
|
|
25
|
+
initialize_defaults(method_name)
|
|
26
|
+
send(method_name, *parameters)
|
|
27
|
+
|
|
28
|
+
# If an explicit, textual body has not been set, we check assumptions.
|
|
29
|
+
unless String === @body
|
|
30
|
+
# First, we look to see if there are any likely templates that match,
|
|
31
|
+
# which include the content-type in their file name (i.e.,
|
|
32
|
+
# "the_template_file.text.html.rhtml", etc.). Only do this if parts
|
|
33
|
+
# have not already been specified manually.
|
|
34
|
+
if @parts.empty?
|
|
35
|
+
append_localized_parts
|
|
36
|
+
unless @parts.empty?
|
|
37
|
+
@content_type = "multipart/alternative"
|
|
38
|
+
@charset = nil
|
|
39
|
+
@parts = sort_parts(@parts, @implicit_parts_order)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Then, if there were such templates, we check to see if we ought to
|
|
44
|
+
# also render a "normal" template (without the content type). If a
|
|
45
|
+
# normal template exists (or if there were no implicit parts) we render
|
|
46
|
+
# it.
|
|
47
|
+
render_localized_normal_template
|
|
48
|
+
|
|
49
|
+
# Finally, if there are other message parts and a textual body exists,
|
|
50
|
+
# we shift it onto the front of the parts and set the body to nil (so
|
|
51
|
+
# that create_mail doesn't try to render it in addition to the parts).
|
|
52
|
+
if !@parts.empty? && String === @body
|
|
53
|
+
@parts.unshift Part.new(:charset => charset, :body => @body)
|
|
54
|
+
@body = nil
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# If this is a multipart e-mail add the mime_version if it is not
|
|
59
|
+
# already set.
|
|
60
|
+
@mime_version ||= "1.0" if !@parts.empty?
|
|
61
|
+
|
|
62
|
+
# build the mail object itself
|
|
63
|
+
@mail = create_mail
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
def append_localized_parts
|
|
69
|
+
codes = locale_codes
|
|
70
|
+
codes.each do |code|
|
|
71
|
+
if code
|
|
72
|
+
templates = Dir.glob("#{template_path}/#{@template}.#{code}.*")
|
|
73
|
+
else
|
|
74
|
+
templates = Dir.glob("#{template_path}/#{@template}.*")
|
|
75
|
+
end
|
|
76
|
+
templates.each do |path|
|
|
77
|
+
sections = File.basename(path).split(".")[0..-2] || []
|
|
78
|
+
|
|
79
|
+
# skip if this is some other language
|
|
80
|
+
next if !code && Globalize::RFC_3066.valid?(sections[1])
|
|
81
|
+
|
|
82
|
+
# skip either template name and locale, or just template name
|
|
83
|
+
type_sections = code ? sections[2..-1] : sections[1..-1]
|
|
84
|
+
type = type_sections.join("/")
|
|
85
|
+
|
|
86
|
+
next if type.empty?
|
|
87
|
+
@parts << Part.new(:content_type => type,
|
|
88
|
+
:disposition => "inline", :charset => charset,
|
|
89
|
+
:body => render_message(sections.join('.'), @body))
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# if we found templates at this stage, no need to continue to defaults
|
|
94
|
+
break if !templates.empty?
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def render_localized_normal_template
|
|
99
|
+
template_exists = @parts.empty?
|
|
100
|
+
codes = locale_codes
|
|
101
|
+
codes.each do |code|
|
|
102
|
+
localized_name = @template
|
|
103
|
+
if !template_exists
|
|
104
|
+
if code
|
|
105
|
+
localized_name = [ @template, code ].join(".")
|
|
106
|
+
template_exists ||=
|
|
107
|
+
Dir.glob("#{template_path}/#{localized_name}.*").any? { |i| i.split(".").length == 3 }
|
|
108
|
+
else
|
|
109
|
+
template_exists ||=
|
|
110
|
+
Dir.glob("#{template_path}/#{@template}.*").any? { |i| i.split(".").length == 2 }
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
@body = render_message(localized_name, @body) if template_exists
|
|
114
|
+
break if template_exists
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def locale_codes
|
|
119
|
+
loc = Globalize::Locale.active
|
|
120
|
+
lang = Globalize::Locale.language
|
|
121
|
+
codes = [ loc, lang ].compact.map {|o| o.code }.uniq
|
|
122
|
+
codes << nil # look for default path, with no localization
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|