jerome-localized-frontend 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 August Lilleaas
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,54 @@
1
+ = Localized Frontend
2
+
3
+ http://gitorious.org/projects/localized-frontend/
4
+ http://github.com/leethal/localized-frontend/
5
+
6
+ Localizing the front-end of single language Rails apps.
7
+
8
+ The localizations are stored in YAML files. Create a spanish.yml file, call
9
+ LocalizedFrontend.in :spanish somewhere in your app (probably in environment.rb or an
10
+ initializer), and rejoice!
11
+
12
+ It localizes inflectors (pluralize, singularize etc), Active Record error messages, month
13
+ and day names, form labels (<%= f.label :foo %>) and Array#to_sentence.
14
+
15
+ == To contributors
16
+
17
+ Feel free to submit your own translations and localizations! You can mail me patches on
18
+ augustlilleaas@gmail.com, or you can fork the Git repository on
19
+ http://github.com/leethal/localized-frontend/ and send a pull request. Or write it down on
20
+ paper and mail it to me. Your call!
21
+
22
+ Keep in mind that the YAML file is whiny - certain keys and values are required in
23
+ order to avoid errors being raised. At the moment, the tests are hardcoded in Norwegian.
24
+ That should probably change, so that one can set the language in an environment
25
+ variable and run the tests in whatever language one might prefer.
26
+
27
+ Also, the code is fairly hard to grok, as it's mostly monkey patches. Feel free to improve
28
+ the readability of the code!
29
+
30
+ == What it does
31
+
32
+ Here's a short list of features (examples are in norwegian)
33
+
34
+ Localizing %b, %B, %a and %A in Time#strftime, Date#strftime and DateTime#strftime
35
+
36
+ * Time.now.strftime('%b') => okt
37
+ * Time.now.strftime('%b') => oktober
38
+ * Time.now.strftime('%a') => søn
39
+ * Time.now.strftime('%A') => søndag
40
+
41
+ Localized inflections. "bil".pluralize => "biler"
42
+
43
+ Localizing attribute names in ActiveRecord.
44
+
45
+ class Question < ActiveRecord::Base
46
+ localized_fields :question => "Spørsmål", :answer => "Svar"
47
+ end
48
+
49
+ == TODO
50
+
51
+ * Make tests runnable in any language. In other words, don't let tests be hardcoded in Norwegian.
52
+
53
+
54
+ Copyright (c) 2008 August Lilleaas, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the translated plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the translated plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'Translated'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
data/TODO ADDED
@@ -0,0 +1,2 @@
1
+ * Look for deprecation errors and kill them on sight!
2
+ * http://github.com/rails/rails/commit/4f75840d72b96fff34d65b59480da7d6c7494120
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'localized_frontend'
@@ -0,0 +1,15 @@
1
+ require 'localized_frontend/core'
2
+ require 'localized_frontend/inflector_extension'
3
+ require 'localized_frontend/active_record_extension'
4
+ require 'localized_frontend/strftime'
5
+ require 'localized_frontend/to_sentence'
6
+ require 'localized_frontend/form_labels'
7
+ require 'localized_frontend/date_helper'
8
+
9
+ module LocalizedFrontend
10
+ # Raised when a localization method is called but the language isn't set. Set it with
11
+ # <tt>LocalizedFrontend.in</tt>.
12
+ class LanguageNotSet < StandardError; end
13
+
14
+ include Core
15
+ end
@@ -0,0 +1,13 @@
1
+ %w(translatable_column_names error_messages).each do |extension|
2
+ require File.join(File.dirname(__FILE__), 'active_record_extension', extension)
3
+ end
4
+
5
+ module LocalizedFrontend
6
+ # Active Record extensions. Refer to child modules for the rock 'n roll.
7
+ module ActiveRecordExtension
8
+ def self.included(base)
9
+ include TranslatableColumnNames
10
+ include ErrorMessages
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+ module LocalizedFrontend
2
+ module ActiveRecordExtension
3
+ # Hooks into Active Record's validations so that error messages returns a localized version of
4
+ # the column names, if defined. See TranslatableColumnNames for information on how to define
5
+ # these localizations.
6
+ module ErrorMessages
7
+ def self.included(base)
8
+ replace_default_error_messages
9
+ hook_human_attribute_name
10
+ end
11
+
12
+ # Merge the localized definitions into Active Record's definitions.
13
+ def self.replace_default_error_messages
14
+ ActiveRecord::Errors.default_error_messages.merge!(LocalizedFrontend['validation_error_messages'].symbolize_keys)
15
+ end
16
+
17
+ # human_attribute_name is what Active Record calls when looking for the attribute name on
18
+ # error messages. This method injects a localization attempt that fallbacks on the default
19
+ # column name representation if no localization was found.
20
+ def self.hook_human_attribute_name
21
+ ActiveRecord::Base.class_eval do
22
+ def self.human_attribute_name(attribute)
23
+ localized_fields[attribute] || attribute.humanize
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,34 @@
1
+ module LocalizedFrontend
2
+ module ActiveRecordExtension
3
+ # Makes localized attribute names defineable in models. Example:
4
+ #
5
+ # class Post < ActiveRecord::Base
6
+ # localized_fields :title => 'Smuuk smiik smakeke'
7
+ # end
8
+ module TranslatableColumnNames
9
+ def self.included(base)
10
+ ActiveRecord::Base.class_inheritable_accessor :localized_attributes
11
+ ActiveRecord::Base.extend ClassMethods
12
+ end
13
+
14
+ module ClassMethods
15
+ # Stores a set of localized attributes in a hash, so that these localized variants can be
16
+ # used to localize validation error messages.
17
+ #
18
+ # class Post < ActiveRecord::Base
19
+ # localized_fields :title => 'Smuuk smiik smakeke'
20
+ # validates_presence_of :title
21
+ # end
22
+ #
23
+ # p = Post.new
24
+ # p.valid?
25
+ # p.errors.full_messages # => ['Smuuk smiik smakeke is required']
26
+ # # (fyi, the 'is required' part can also be localized)
27
+ def localized_fields(options = {})
28
+ self.localized_attributes ||= HashWithIndifferentAccess.new
29
+ self.localized_attributes.merge!(options)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,62 @@
1
+ module LocalizedFrontend
2
+ # The main module that adds class methods to LocalizedFrontend and creates the hooks we need. See
3
+ # the individual methods for more information.
4
+ module Core
5
+ # Creates the LocalizedFrontend.language accessor and stuff.
6
+ def self.included(base)
7
+ base.mattr_accessor :language
8
+ base.extend ClassMethods
9
+ end
10
+
11
+ module ClassMethods
12
+ # Sets the current language.
13
+ #
14
+ # LocalizedFrontend.in :french
15
+ def in(language)
16
+ self.language = language
17
+ first_time_inclusion
18
+ change_language!
19
+ end
20
+
21
+ # Returns the current language as a hash, or raises LanguageNotSet if (woha) the language isn't set.
22
+ def current_language(reload = false)
23
+ begin
24
+ @current_language = nil if reload
25
+ @current_language ||= YAML::load_file(File.join(File.dirname(__FILE__), "..", "translations", "#{language}.yml"))
26
+ rescue Errno::ENOENT
27
+ raise LocalizedFrontend::LanguageNotSet
28
+ end
29
+ end
30
+
31
+ # A shortcut to current language. These are equivalents:
32
+ #
33
+ # LocalizedFrontend.current_language['foos']
34
+ # LocalizedFrontend['foos']
35
+ def [](key)
36
+ current_language[key]
37
+ end
38
+
39
+ private
40
+
41
+ # Dirty. Fix, please.
42
+ def first_time_inclusion
43
+ return if @included
44
+
45
+ LocalizedFrontend.class_eval do
46
+ include InflectorExtension
47
+ include ActiveRecordExtension
48
+ include Strftime
49
+ include ToSentence
50
+ include FormLabels
51
+ end
52
+
53
+ @included = true
54
+ end
55
+
56
+ def change_language!
57
+ # Reload the current language hash.
58
+ current_language(true)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,36 @@
1
+ module LocalizedFrontend
2
+ module DateHelper
3
+ def self.included(base)
4
+ ActionView::Helpers::DateHelper.class_eval do
5
+ def select_month_with_localization(date, options = {}, html_options = {})
6
+ val = date ? (date.kind_of?(Fixnum) ? date : date.month) : ''
7
+ if options[:use_hidden]
8
+ hidden_html(options[:field_name] || 'month', val, options)
9
+ else
10
+ month_options = []
11
+ month_names = options[:use_month_names] || (options[:use_short_month] ? LocalizedFrontend['month_names']['abbreviated']: LocalizedFrontend['month_names']['full'])
12
+ month_names.unshift(nil) if month_names.size < 13
13
+ 1.upto(12) do |month_number|
14
+ month_name = if options[:use_month_numbers]
15
+ month_number
16
+ elsif options[:add_month_numbers]
17
+ month_number.to_s + ' - ' + month_names[month_number]
18
+ else
19
+ month_names[month_number]
20
+ end
21
+
22
+ month_options << ((val == month_number) ?
23
+ content_tag(:option, month_name, :value => month_number, :selected => "selected") :
24
+ content_tag(:option, month_name, :value => month_number)
25
+ )
26
+ month_options << "\n"
27
+ end
28
+ select_html(options[:field_name] || 'month', month_options.join, options, html_options)
29
+ end
30
+ end
31
+ end
32
+
33
+ ActionView::Helpers::DateHelper.alias_method_chain :select_month, :localization
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,20 @@
1
+ module LocalizedFrontend
2
+ # The default form builders label method tries to find a localized definition
3
+ # of the attribute.
4
+ #
5
+ # <%= f.label :title %> (returns 'Localized Version of Title That Is Defined In the Model')
6
+ module FormLabels
7
+ def self.included(base)
8
+ ActionView::Helpers::FormBuilder.class_eval do
9
+ def label_with_localization(method, text = nil, options = {})
10
+ if @object
11
+ text ||= @object.class.localized_attributes ? @object.class.localized_attributes[method] : nil
12
+ end
13
+ label_without_localization(method, text, options)
14
+ end
15
+ end
16
+
17
+ ActionView::Helpers::FormBuilder.alias_method_chain :label, :localization
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,131 @@
1
+ module LocalizedFrontend
2
+ # Handles localization of inflections (pluralize, singularize etc.)
3
+ module InflectorExtension
4
+ def self.included(base)
5
+ add_localized_pluralizations_to_string
6
+ extend_inflector_class
7
+ initialize_localized_rules
8
+ set_localized_inflections
9
+ end
10
+
11
+ # Adds the local_puralize and local_singularize methods to String. These methods are
12
+ # used to get a localized pluralization/singularization.
13
+ #
14
+ # LocalizedFrontend.in :norwegian
15
+ # "car".pluralize # => "cars"
16
+ # "car".local_pluralize # => "carer"
17
+ # "bil".local_pluralize # => "biler"
18
+ def self.add_localized_pluralizations_to_string
19
+ String.class_eval { include StringInstanceMethods }
20
+ end
21
+
22
+ # Hooks into the inflector instance and adds the methods we need in order to get
23
+ # localized inflections. The real meat is the in_localized_scope method.
24
+ def self.extend_inflector_class
25
+ Inflector.inflections.class.class_eval { attr_accessor :localize }
26
+ Inflector.inflections.instance_eval { extend InflectorInstanceMethods }
27
+ end
28
+
29
+ # We store the localized inflections in a separate set of instance variables. See
30
+ # InflectorInstanceMethods
31
+ def self.initialize_localized_rules
32
+ Inflector.inflections.instance_eval do
33
+ @localized_plurals, @localized_singulars, @localized_uncountables = [], [], []
34
+ end
35
+ end
36
+
37
+ # The real meat that loops through the defined inflections and hooks them into the
38
+ # monkey patched Inflector.
39
+ def self.set_localized_inflections
40
+ Inflector.inflections.plurals
41
+ Inflector.inflections.in_localized_scope do
42
+ Inflector.inflections.current_scope('plurals')
43
+ end
44
+ Inflector.inflections.in_localized_scope do
45
+ %w(singular plural irregular).each do |type|
46
+ next unless LocalizedFrontend['inflections'][type]
47
+
48
+ LocalizedFrontend['inflections'][type].each do |rule, replacement|
49
+ Inflector.inflections.send(type, case_insensitive_regular_expression(rule), replacement)
50
+ end
51
+ end
52
+
53
+ Inflector.inflections.uncountable(LocalizedFrontend['inflections']['uncountable'])
54
+ end
55
+ end
56
+
57
+ # That's what the 'true' means. Case insensitive.
58
+ def self.case_insensitive_regular_expression(rule)
59
+ Regexp.new(rule, true)
60
+ end
61
+
62
+ # The in_localized_scope method is the only thing you need here. Everything else is obscure
63
+ # and retarded.
64
+ #
65
+ # The methods +plural+, +singular+ and +uncountable+ is a simple re-definition of the original
66
+ # method in Inflector. The change is simple - use methods instead of instance variables. So, when
67
+ # the +plural+ method used to do @plurals.insert, we change it so that it does plurals.insert. Then,
68
+ # these methods (+singulars+, +plurals+ and +uncountables+) are returning the inflections we want in
69
+ # the language we request. If +Inflector.inflections.localize+ is set to true, we'll get
70
+ # @localized_plurals. If it's set to false, we get the default @plurals (which the original,
71
+ # un-overrided methods was originally using).
72
+ #
73
+ # +irregulars+ are not re-defined, as that method is calling the +plural+ and +singular+ methods
74
+ # anyway. Which we have already overrided.
75
+ module InflectorInstanceMethods
76
+ # Sets the scope as localized. This is what String#local_pluralize and friends does.
77
+ #
78
+ # "car".pluralize # => "cars"
79
+ # "car".localized_pluralize # => "carer"
80
+ # Inflector.inflections.in_localized_scope { "car".pluralize } # => "carer"
81
+ def in_localized_scope(&block)
82
+ self.localize = true
83
+ result = yield
84
+ self.localize = false
85
+
86
+ result
87
+ end
88
+
89
+ def current_scope(type)
90
+ prefix = localize ? "localized_" : nil
91
+ instance_variable_get("@#{prefix}#{type}")
92
+ end
93
+
94
+ def singulars
95
+ current_scope(:singulars)
96
+ end
97
+
98
+ def plurals
99
+ current_scope(:plurals)
100
+ end
101
+
102
+ def uncountables
103
+ current_scope(:uncountables)
104
+ end
105
+
106
+ def plural(rule, replacement)
107
+ plurals.insert(0, [rule, replacement])
108
+ end
109
+
110
+ def singular(rule, replacement)
111
+ singulars.insert(0, [rule, replacement])
112
+ end
113
+
114
+ def uncountable(*words)
115
+ (uncountables << words).flatten!
116
+ end
117
+ end
118
+
119
+ module StringInstanceMethods
120
+ # A localized version of String#pluralize
121
+ def local_pluralize
122
+ Inflector.inflections.in_localized_scope { pluralize }
123
+ end
124
+
125
+ # A localized version of String#singularize
126
+ def local_singularize
127
+ Inflector.inflections.in_localized_scope { singularize }
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,36 @@
1
+ module LocalizedFrontend
2
+ # Localizes Time#strftime, Date#strftime and DateTime#strftime.
3
+ module Strftime
4
+ # Includes the InstanceMethods module into Time, Date and DateTime.
5
+ def self.included(base)
6
+ [Time, Date, DateTime].each do |klass|
7
+ klass.class_eval { include InstanceMethods }
8
+ end
9
+ end
10
+
11
+ module InstanceMethods
12
+ def self.included(base)
13
+ base.alias_method_chain :strftime, :localization
14
+ end
15
+
16
+ # A rather ugly hack that gsubs the keys we're looking for and replaces it with
17
+ # localized strings, and then passes the format string to the original strftime
18
+ # method. "%Y %B" turns into, say, "%Y Juni", and is passed to strftime.
19
+ #
20
+ # Time/Date/DateTime#strftime_without_localization can be called in order to
21
+ # bypass this.
22
+ def strftime_with_localization(format = '%F')
23
+ _weekday = self.wday - 1
24
+ _month = self.month - 1
25
+
26
+ format.gsub!(/%a/, LocalizedFrontend['day_names']['abbreviated'][_weekday])
27
+ format.gsub!(/%A/, LocalizedFrontend['day_names']['full'][_weekday])
28
+
29
+ format.gsub!(/%b/, LocalizedFrontend['month_names']['abbreviated'][_month])
30
+ format.gsub!(/%B/, LocalizedFrontend['month_names']['full'][_month])
31
+
32
+ strftime_without_localization(format)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ module LocalizedFrontend
2
+ # Localizes the connector and the skip_last_comma settings for Array#to_sentence
3
+ module ToSentence
4
+ def self.included(base)
5
+ Array.class_eval { include InstanceMethods }
6
+ end
7
+
8
+ module InstanceMethods
9
+ def self.included(base)
10
+ base.alias_method_chain :to_sentence, :localization
11
+ end
12
+
13
+ def to_sentence_with_localization(options = {})
14
+ options.reverse_merge! :connector => LocalizedFrontend['to_sentence']['connector'], :skip_last_comma => LocalizedFrontend['to_sentence']['skip_last_comma']
15
+ to_sentence_without_localization(options)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,59 @@
1
+ day_names:
2
+ abbreviated:
3
+ - Dim
4
+ - Lun
5
+ - Mar
6
+ - Mer
7
+ - Jeu
8
+ - Ven
9
+ - Sam
10
+ full:
11
+ - Dimanche
12
+ - Lundi
13
+ - Mardi
14
+ - Mercredi
15
+ - Jeudi
16
+ - Vendredi
17
+ - Samedi
18
+
19
+ month_names:
20
+ abbreviated:
21
+ - jan
22
+ - fév
23
+ - mar
24
+ - avr
25
+ - mai
26
+ - jun
27
+ - jul
28
+ - aou
29
+ - sep
30
+ - oct
31
+ - nov
32
+ - dec
33
+ full:
34
+ - janvier
35
+ - février
36
+ - mars
37
+ - avril
38
+ - mai
39
+ - juin
40
+ - juillet
41
+ - août
42
+ - septembre
43
+ - octobre
44
+ - novembre
45
+ - décembre
46
+
47
+ inflections:
48
+ plural:
49
+ '$': 's'
50
+ singular:
51
+ 's$': ''
52
+ uncountable:
53
+
54
+ to_sentence:
55
+ connector: et
56
+ skip_last_comma: true
57
+
58
+ validation_error_messages:
59
+ inclusion: n'est pas dans la liste
@@ -0,0 +1,79 @@
1
+ day_names:
2
+ abbreviated:
3
+ - Søn
4
+ - Man
5
+ - Tir
6
+ - Ons
7
+ - Tor
8
+ - Fre
9
+ - Lør
10
+ full:
11
+ - Søndag
12
+ - Mandag
13
+ - Tirsdag
14
+ - Onsdag
15
+ - Torsdag
16
+ - Fredag
17
+ - Lørdag
18
+
19
+ month_names:
20
+ abbreviated:
21
+ - Jan
22
+ - Feb
23
+ - Mar
24
+ - Apr
25
+ - Mai
26
+ - Jun
27
+ - Jul
28
+ - Aug
29
+ - Sep
30
+ - Okt
31
+ - Nov
32
+ - Des
33
+ full:
34
+ - Januar
35
+ - Februar
36
+ - Mars
37
+ - April
38
+ - Mai
39
+ - Juni
40
+ - Juli
41
+ - August
42
+ - September
43
+ - Oktober
44
+ - November
45
+ - Desember
46
+
47
+ inflections:
48
+ plural:
49
+ '$': 'er'
50
+ singular:
51
+ 'er$': ''
52
+ uncountable:
53
+ - hus
54
+ - tak
55
+
56
+ to_sentence:
57
+ connector: og
58
+ skip_last_comma: true
59
+
60
+ validation_error_messages:
61
+ inclusion: er ikke i lista
62
+ exclusion: er reservert
63
+ invalid: er ugyldig
64
+ confirmation: stemmer ikke overens
65
+ accepted: må aksepteres
66
+ empty: må fylles ut
67
+ blank: må fylles ut
68
+ too_long: er for lang (maks %d tegn)
69
+ too_short: er for kort (minst %d tegn)
70
+ wrong_length: har feil lengde (skal være %d tegn)
71
+ taken: er allerede tatt
72
+ not_a_number: må være et tall
73
+ greater_than: må være høyere enn %d
74
+ greater_than_or_equal_to: må være høyere enn eller lik %d
75
+ equal_to: må være %d
76
+ less_than: må være mindre enn %d
77
+ less_than_or_equal_to: må være mindre enn eller lik %d
78
+ odd: må være et oddetall
79
+ even: må være et partall
@@ -0,0 +1,25 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class ActiveRecordExtensionTest < Test::Unit::TestCase
4
+ def test_table_name_pluralization
5
+ assert_equal 'posts', Post.table_name
6
+ end
7
+
8
+ def test_setting_localized_fields
9
+ assert_equal 'Tittel', Post.localized_fields[:title]
10
+ assert_equal 'Tittel', Post.localized_fields['title']
11
+ end
12
+
13
+ def test_overriding_default_error_messages
14
+ assert_equal ActiveRecord::Errors.default_error_messages[:too_short], LocalizedFrontend['validation_error_messages']['too_short']
15
+ end
16
+
17
+ def test_actual_error_message_output
18
+ message = ActiveRecord::Errors.default_error_messages[:blank]
19
+ p = Post.new
20
+ p.valid?
21
+
22
+ assert_equal message, p.errors.on(:title)
23
+ assert p.errors.full_messages.include?("Tittel #{message}")
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ require File.join(File.dirname(__FILE__), "test_helper")
2
+
3
+ class EverythingElseTest < Test::Unit::TestCase
4
+ def test_to_sentence
5
+ assert_equal 'Per, Pål og Espen Askeladd', ['Per', 'Pål', 'Espen Askeladd'].to_sentence
6
+ assert_equal 'Du, jeg, eller meg', ['Du', 'jeg', 'meg'].to_sentence(:connector => 'eller', :skip_last_comma => false)
7
+ end
8
+
9
+ def test_to_sentence_again
10
+ assert_equal 'Per, Pål og Espen Askeladd', ['Per', 'Pål', 'Espen Askeladd'].to_sentence
11
+ assert_equal 'Du, jeg, eller meg', ['Du', 'jeg', 'meg'].to_sentence(:connector => 'eller', :skip_last_comma => false)
12
+ end
13
+ end
@@ -0,0 +1,41 @@
1
+ require File.join(File.dirname(__FILE__), "test_helper")
2
+
3
+ class TranslatedTest < Test::Unit::TestCase
4
+ def setup
5
+ LocalizedFrontend.in :norwegian
6
+
7
+ @controller = DummyController.new
8
+ @request = @controller.request
9
+
10
+ @view = ActionView::Base.new
11
+ @view.assigns['controller'] = @controller
12
+ @view.assigns['_request'] = @request
13
+ @view.assigns['_params'] = @request.params
14
+ end
15
+
16
+ def test_localized_label
17
+ render '<% form_for(Post.new) do |f| %><%= f.label :excerpt %><%= f.label :cheese %><% end %>'
18
+ assert @output =~ Regexp.new('<label for="post_excerpt">Ingress</label>')
19
+ #raise @output.inspect
20
+ end
21
+
22
+ def test_original_label
23
+ render '<% form_for(Post.new) do |f| %><%= f.label :excerpt %><%= f.label :cheese %><% end %>'
24
+ assert @output =~ Regexp.new('<label for="post_cheese">Cheese</label>')
25
+ end
26
+
27
+ def test_unlocalized_model
28
+ render '<% form_for(UnlocalizedFoo.new) do |f| %><%= f.label :foo %><% end %>'
29
+ assert @output =~ Regexp.new('<label for="unlocalized_foo_foo">Foo</label>')
30
+ end
31
+
32
+ def test_symbol
33
+ render '<% form_for(:foo) do |f| %><%= f.label :bar %><% end %>'
34
+ end
35
+
36
+ private
37
+
38
+ def render(template)
39
+ @output = @view.render_template(ActionView::InlineTemplate.new(@view, template))
40
+ end
41
+ end
@@ -0,0 +1,38 @@
1
+ require File.join(File.dirname(__FILE__), "test_helper")
2
+
3
+ class InflectorTest < Test::Unit::TestCase
4
+ def test_original_english_inflections
5
+ assert_equal 'posts', 'post'.pluralize
6
+ assert_equal 'post', 'posts'.singularize
7
+ end
8
+
9
+ def test_singularize
10
+ {"biler" => "bil", "katter" => "katt"}.each do |plural, singular|
11
+ assert_equal singular, plural.local_singularize
12
+ end
13
+ end
14
+
15
+ def test_pluralize
16
+ {"bil" => "biler", "katt" => "katter"}.each do |singular, plural|
17
+ assert_equal plural, singular.local_pluralize
18
+ end
19
+ end
20
+
21
+ def test_irregular
22
+
23
+ end
24
+
25
+ def test_pluralize_uncountable
26
+ %w(hus tak).each do |uncountable|
27
+ assert_equal uncountable, uncountable.local_pluralize
28
+ end
29
+ end
30
+
31
+ def test_adding_inflections
32
+
33
+ end
34
+
35
+ def test_case_insensivity
36
+ assert_equal "BIL", "BILER".local_singularize
37
+ end
38
+ end
@@ -0,0 +1,29 @@
1
+ require File.join(File.dirname(__FILE__), "test_helper")
2
+
3
+ class StrftimeTest < Test::Unit::TestCase
4
+ def test_localized_strftime_on_time
5
+ assert_localized_strftime Time.now
6
+ end
7
+
8
+ def test_localized_strftime_on_date
9
+ assert_localized_strftime Date.today
10
+ end
11
+
12
+ def test_localized_stfrtime_on_datetime
13
+ assert_localized_strftime DateTime.class_eval { today }
14
+ end
15
+
16
+ def test_localized_stfrtime_on_april_fools_day
17
+ assert_equal Time.utc(2008,4,1).strftime("%B"), "April"
18
+ end
19
+
20
+ private
21
+
22
+ def assert_localized_strftime(time)
23
+ assert_equal LocalizedFrontend['month_names']['abbreviated'][time.month-1], time.strftime("%b")
24
+ assert_equal LocalizedFrontend['month_names']['full'][time.month-1], time.strftime("%B")
25
+
26
+ assert_equal LocalizedFrontend['day_names']['abbreviated'][time.wday-1], time.strftime("%a")
27
+ assert_equal LocalizedFrontend['day_names']['full'][time.wday-1], time.strftime("%A")
28
+ end
29
+ end
@@ -0,0 +1,77 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'active_support'
4
+ require 'active_record'
5
+ require 'action_controller'
6
+ require 'action_controller/test_process'
7
+
8
+ require File.join(File.dirname(__FILE__), "..", "lib", "localized_frontend")
9
+ LocalizedFrontend.in :norwegian
10
+
11
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
12
+ ActiveRecord::Schema.define(:version => 1) do
13
+ create_table :posts do |t|
14
+ t.string :title, :cheese
15
+ t.text :excerpt, :body
16
+ end
17
+
18
+ create_table(:unlocalized_foos) {|t| t.string :foo }
19
+ end
20
+
21
+ class Post < ActiveRecord::Base
22
+ localized_fields :title => "Tittel", :excerpt => "Ingress", :body => "Brødtekst"
23
+
24
+ validates_presence_of :title, :excerpt, :body
25
+ end
26
+
27
+ class UnlocalizedFoo < ActiveRecord::Base
28
+ end
29
+
30
+ # The following is ninjaed from will_paginate.
31
+ ActionController::Routing::Routes.draw do |map|
32
+ map.resources :posts, :unlocalized_foos
33
+ map.connect ':controller/:action/:id'
34
+ end
35
+ ActionController::Base.perform_caching = false
36
+
37
+ class ActionView::Base
38
+ def protect_against_forgery?
39
+ false
40
+ end
41
+ end
42
+ class DummyRequest
43
+ attr_accessor :symbolized_path_parameters
44
+
45
+ def initialize
46
+ @get = true
47
+ @params = {}
48
+ @symbolized_path_parameters = { :controller => 'foo', :action => 'bar' }
49
+ end
50
+
51
+ def relative_url_root
52
+ ''
53
+ end
54
+
55
+ def params(more = nil)
56
+ @params.update(more) if more
57
+ @params
58
+ end
59
+ end
60
+
61
+ class DummyController
62
+ attr_reader :request
63
+ attr_accessor :controller_name
64
+
65
+ def initialize
66
+ @request = DummyRequest.new
67
+ @url = ActionController::UrlRewriter.new(@request, @request.params)
68
+ end
69
+
70
+ def params
71
+ @request.params
72
+ end
73
+
74
+ def url_for(params)
75
+ @url.rewrite(params)
76
+ end
77
+ end
@@ -0,0 +1,28 @@
1
+ require File.join(File.dirname(__FILE__), "test_helper")
2
+
3
+ class TranslatedTest < Test::Unit::TestCase
4
+ def test_setting_language
5
+ LocalizedFrontend.in :norwegian
6
+ assert_equal :norwegian, LocalizedFrontend.language
7
+ end
8
+
9
+ def test_fails_with_no_language_set
10
+ LocalizedFrontend.language = nil
11
+ assert_raises(LocalizedFrontend::LanguageNotSet) { LocalizedFrontend.current_language(true) }
12
+ assert_raises(LocalizedFrontend::LanguageNotSet) { LocalizedFrontend['month_names'] }
13
+ end
14
+
15
+ def test_current_language
16
+ assert LocalizedFrontend.current_language.is_a?(Hash)
17
+ end
18
+
19
+ def test_accessing_with_brackets
20
+ assert_equal LocalizedFrontend['month_names'], LocalizedFrontend.current_language['month_names']
21
+ end
22
+
23
+ def test_changing_language
24
+ norwegian = LocalizedFrontend.current_language.dup
25
+ LocalizedFrontend.in :french
26
+ assert_not_equal norwegian, LocalizedFrontend.current_language
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jerome-localized-frontend
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - August Lilleaas
8
+ - "J\xC3\xA9r\xC3\xB4me Lipowicz"
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2008-10-10 00:00:00 -07:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description:
18
+ email: augustlilleaas@gmail.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files: []
24
+
25
+ files:
26
+ - init.rb
27
+ - MIT-LICENSE
28
+ - Rakefile
29
+ - README
30
+ - TODO
31
+ - lib/localized_frontend.rb
32
+ - lib/localized_frontend/active_record_extension.rb
33
+ - lib/localized_frontend/core.rb
34
+ - lib/localized_frontend/date_helper.rb
35
+ - lib/localized_frontend/form_labels.rb
36
+ - lib/localized_frontend/inflector_extension.rb
37
+ - lib/localized_frontend/strftime.rb
38
+ - lib/localized_frontend/to_sentence.rb
39
+ - lib/translations/french.yml
40
+ - lib/translations/norwegian.yml
41
+ - lib/localized_frontend/active_record_extension/error_messages.rb
42
+ - lib/localized_frontend/active_record_extension/translatable_column_names.rb
43
+ has_rdoc: false
44
+ homepage: http://github.com/leethal/localized-frontend/
45
+ post_install_message:
46
+ rdoc_options: []
47
+
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ requirements: []
63
+
64
+ rubyforge_project:
65
+ rubygems_version: 1.2.0
66
+ signing_key:
67
+ specification_version: 2
68
+ summary: Localize the frontend of single language Rails apps.
69
+ test_files:
70
+ - test/active_record_test.rb
71
+ - test/everything_else_test.rb
72
+ - test/form_labels_test.rb
73
+ - test/inflector_test.rb
74
+ - test/strftime_test.rb
75
+ - test/test_helper.rb
76
+ - test/translated_test.rb