snusnu-dm-is-localizable 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ test_log
2
+ pkg
3
+ pkg/*
4
+ */pkg/*
5
+ bundle
6
+ bundle/*
7
+ doc
8
+ *.log
9
+ log
10
+ !log*.rb
11
+ */log
12
+ log/*
13
+ */log/*
14
+ coverage
15
+ */coverage
16
+ lib/dm-more.rb
17
+ *.db
18
+ nbproject
19
+ .DS_Store
20
+ rspec_report.html
21
+ *.swp
22
+ _Yardoc
23
+ */ri
data/CHANGELOG ADDED
@@ -0,0 +1,183 @@
1
+ [e66cccc | Sat May 16 19:02:07 UTC 2009] snusnu <gamsnjaga@gmail.com>
2
+
3
+ * Version bump to 0.0.4
4
+
5
+ [963611b | Sat May 16 19:00:47 UTC 2009] snusnu <gamsnjaga@gmail.com>
6
+
7
+ * README corrections to reflect the recently added uniqueness constraints
8
+
9
+ [47c5e1e | Sat May 16 18:56:09 UTC 2009] snusnu <gamsnjaga@gmail.com>
10
+
11
+ * added passing specs for unique language translations
12
+
13
+ [fd37d64 | Sat May 16 18:55:09 UTC 2009] snusnu <gamsnjaga@gmail.com>
14
+
15
+ * more comprehensive unique constraint violation checks for language
16
+
17
+ [15a9626 | Sat May 16 18:34:13 UTC 2009] snusnu <gamsnjaga@gmail.com>
18
+
19
+ * added passing spec for unique language codes
20
+
21
+ [20242b3 | Sat May 16 18:17:19 UTC 2009] snusnu <gamsnjaga@gmail.com>
22
+
23
+ * split spec files into better manageable chunks
24
+
25
+ [f4b6d30 | Sat May 16 17:32:46 UTC 2009] snusnu <gamsnjaga@gmail.com>
26
+
27
+ * moved rspec_tmbundle_support from specs/shared to specs/lib
28
+
29
+ [12fe27a | Sat May 16 17:26:30 UTC 2009] snusnu <gamsnjaga@gmail.com>
30
+
31
+ * added TODO file
32
+
33
+ [c66d793 | Sat May 16 17:22:51 UTC 2009] snusnu <gamsnjaga@gmail.com>
34
+
35
+ * added more class and instance level API.
36
+
37
+ These API methods mainly target the support for a UI that allows
38
+ clients to enter localized versions of their textual data (and
39
+ find out if they already completed their translations for specific
40
+ resources).
41
+
42
+ added class level API
43
+
44
+ * available_languages
45
+ * nr_of_available_languages
46
+ * translations_complete?
47
+
48
+ instance level API
49
+
50
+ * available_languages
51
+ * nr_of_available_languages
52
+ * translations_complete?
53
+
54
+ [cb462f4 | Sat May 16 17:13:57 UTC 2009] snusnu <gamsnjaga@gmail.com>
55
+
56
+ * added support for nice html output in rspec tmbundle.
57
+
58
+ [f713c84 | Sat May 16 05:33:54 UTC 2009] snusnu <gamsnjaga@gmail.com>
59
+
60
+ * Version bump to 0.0.3
61
+
62
+ [aa6188c | Sat May 16 05:33:44 UTC 2009] snusnu <gamsnjaga@gmail.com>
63
+
64
+ * added available_languages instance level API
65
+
66
+ [d5f13e1 | Sat May 16 05:12:03 UTC 2009] snusnu <gamsnjaga@gmail.com>
67
+
68
+ * README correction (available_languages is a class method)
69
+
70
+ [92bf341 | Sat May 16 05:06:05 UTC 2009] snusnu <gamsnjaga@gmail.com>
71
+
72
+ * Version bump to 0.0.2
73
+
74
+ [8de6a08 | Sat May 16 05:00:33 UTC 2009] snusnu <gamsnjaga@gmail.com>
75
+
76
+ * added specs for the translations and languages association.
77
+
78
+ I wonder if available_languages should be implemeted on top of
79
+ has n, :languages, :through => :translations
80
+
81
+ [dd4830f | Sat May 16 04:51:23 UTC 2009] snusnu <gamsnjaga@gmail.com>
82
+
83
+ * added available_languages class method API
84
+
85
+ [3596021 | Sat May 16 04:37:45 UTC 2009] snusnu <gamsnjaga@gmail.com>
86
+
87
+ * use transactional fixtures and have the loggers handy
88
+
89
+ [fa00b88 | Sat May 16 04:07:10 UTC 2009] snusnu <gamsnjaga@gmail.com>
90
+
91
+ * enforce unique language codes (locale strings)
92
+
93
+ [b7b8221 | Sat May 16 04:01:59 UTC 2009] snusnu <gamsnjaga@gmail.com>
94
+
95
+ * added missing spec for translation_class reader
96
+
97
+ [b0cd326 | Sat May 16 03:43:33 UTC 2009] snusnu <gamsnjaga@gmail.com>
98
+
99
+ * translation_class reader instead of translation_class_name
100
+
101
+ [d34352b | Sat May 16 03:31:54 UTC 2009] snusnu <gamsnjaga@gmail.com>
102
+
103
+ * jeweler generated gemspec
104
+
105
+ [0ddc194 | Sat May 16 03:28:33 UTC 2009] snusnu <gamsnjaga@gmail.com>
106
+
107
+ * Version bump to 0.0.1
108
+
109
+ [5abddb9 | Sat May 16 03:28:06 UTC 2009] snusnu <gamsnjaga@gmail.com>
110
+
111
+ * Version bump to 0.0.0
112
+
113
+ [25ace0a | Sat May 16 03:26:39 UTC 2009] snusnu <gamsnjaga@gmail.com>
114
+
115
+ * updated README to reflect validations for Language
116
+
117
+ [8f78083 | Sat May 16 03:24:00 UTC 2009] snusnu <gamsnjaga@gmail.com>
118
+
119
+ * validations and specs for Language.
120
+
121
+ * Think about locale string validation.
122
+ * Currently this is only a regex
123
+ * Should THIS be checked against a full list of possible locales?
124
+
125
+ [d1c0a25 | Sat May 16 03:23:01 UTC 2009] snusnu <gamsnjaga@gmail.com>
126
+
127
+ * proper namespace for module Translation
128
+
129
+ [982e081 | Sat May 16 03:21:29 UTC 2009] snusnu <gamsnjaga@gmail.com>
130
+
131
+ * added gem dependencies to gem specification and spec_helper
132
+
133
+ [8cf2113 | Sat May 16 00:57:17 UTC 2009] snusnu <gamsnjaga@gmail.com>
134
+
135
+ * README cosmetics
136
+
137
+ [8507bab | Sat May 16 00:27:42 UTC 2009] snusnu <gamsnjaga@gmail.com>
138
+
139
+ * updated README with usage examples.
140
+
141
+ [d277892 | Fri May 15 23:49:27 UTC 2009] snusnu <gamsnjaga@gmail.com>
142
+
143
+ * updated LICENSE information
144
+
145
+ [f6655c8 | Fri May 15 21:42:44 UTC 2009] snusnu <gamsnjaga@gmail.com>
146
+
147
+ * basic storage layout functional and tested. now add useful API.
148
+
149
+ * one xxx_translations table for every translatable resource
150
+ * belongs_to the resource to translate
151
+ * belongs_to a language
152
+ * properties to be translated are defined in xxx_translations
153
+
154
+ Example
155
+
156
+ class Item
157
+ include DataMapper::Resource
158
+ property :id, Serial
159
+ is :localizable do
160
+ property :name, String, :nullable => false
161
+ property :desc, String, :nullable => false
162
+ end
163
+ end
164
+
165
+ Advantages
166
+
167
+ * Proper normalization and referential integrity
168
+ * Ease in adding a new language (add row to xxx_translations)
169
+ * Easy to query
170
+ * Columns keep there names
171
+
172
+ Disadvantages (not really if you think about it)
173
+
174
+ * one table for every tables resource that needs translations
175
+
176
+ Inspired by
177
+
178
+ option 4) at http://is.gd/Af0d
179
+
180
+ [bebfb8d | Fri May 15 13:57:49 UTC 2009] snusnu <gamsnjaga@gmail.com>
181
+
182
+ * Initial commit to dm-is-localizable.
183
+
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Martin Gamsjaeger (snusnu)
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.textile ADDED
@@ -0,0 +1,177 @@
1
+ h1. dm-is-localizable
2
+
3
+ Datamapper support for localization of (user entered) content in multilanguage applications
4
+
5
+ h3. Schema
6
+
7
+ * one xxx_translations table for every translatable resource
8
+ * xxx_translations belongs_to the resource to translate
9
+ * xxx_translations belongs_to a language
10
+ * properties to be translated are defined in xxx_translations
11
+
12
+
13
+ h4. Advantages
14
+
15
+ * Proper normalization and referential integrity
16
+ * Ease in adding a new language (add row to xxx_translations)
17
+ * Easy to query
18
+ * Columns keep their names
19
+
20
+
21
+ h4. Disadvantages (not really if you think about it)
22
+
23
+ * One table for every resource that needs translations
24
+
25
+
26
+ h3. Example definition of a localized model
27
+
28
+ Currently, you need to define a @Language@ model yourself, to get @dm-is-localizable@ started.
29
+
30
+ <pre>
31
+ <code>
32
+ class Language
33
+
34
+ include DataMapper::Resource
35
+
36
+ # properties
37
+
38
+ property :id, Serial
39
+
40
+ property :code, String, :nullable => false, :unique => true, :unique_index => true
41
+ property :name, String, :nullable => false
42
+
43
+ # locale string like 'en-US'
44
+ validates_format :code, :with => /^[a-z]{2}-[A-Z]{2}$/
45
+
46
+ end
47
+ </code>
48
+ </pre>
49
+
50
+ Once you have this model in place, you can start defining your _localized models_.
51
+
52
+ <pre>
53
+ <code>
54
+ class Item
55
+
56
+ include DataMapper::Resource
57
+
58
+ property :id, Serial
59
+
60
+ is :localizable do
61
+ property :name, String
62
+ property :desc, String
63
+ end
64
+
65
+ end
66
+ </code>
67
+ </pre>
68
+
69
+ The above @Item@ model will define and thus be able to @DataMapper.auto_migrate!@ the @ItemTranslation@ model. The _naming convention_ used here is @"#{ClassToBeLocalized.name}Translation"@.
70
+
71
+ Preliminary support for changing this is available by using the @:class_name@ option like so: @DataMapper::Model.is :localized, :class_name => 'ItemLocalization'@. However, this currently not yet specced.
72
+
73
+ <pre>
74
+ <code>
75
+ class ItemTranslation
76
+
77
+ include DataMapper::Resource
78
+
79
+ property :id, Serial
80
+
81
+ property :item_id, Integer, :nullable => false, :unique_index => :unique_languages
82
+ property :language_id, Integer, :nullable => false, :unique_index => :unique_languages
83
+
84
+ property :name, String
85
+ property :desc, String
86
+
87
+ belongs_to :item
88
+ belongs_to :language
89
+
90
+ end
91
+ </code>
92
+ </pre>
93
+
94
+ Furthermore, the following API gets defined on the @Item@ class:
95
+
96
+ <pre>
97
+ <code>
98
+ class Item
99
+
100
+ include DataMapper::Resource
101
+
102
+ property :id, Serial
103
+
104
+ is :localizable do
105
+ property :name, String
106
+ property :desc, String
107
+ end
108
+
109
+ # ----------------------------
110
+ # added by is :localizable
111
+ # ----------------------------
112
+
113
+ has n, :item_translations
114
+ has n, :languages, :through => :item_translations
115
+
116
+ # and a handy alias
117
+ alias :translations :item_translations
118
+
119
+ # helper to get at ItemTranslation
120
+ class_inheritable_reader :translation_class
121
+
122
+ # -------------------
123
+ # class level API
124
+ # -------------------
125
+
126
+ # list all available languages for Items
127
+ def self.available_languages
128
+ Language.all :id => translation_class.all.map { |t| t.language_id }.uniq
129
+ end
130
+
131
+ # the number of all available languages for the localizable model
132
+ def self.nr_of_available_languages
133
+ available_languages.size
134
+ end
135
+
136
+ # checks if all localizable resources are translated in all available languages
137
+ def self.translations_complete?
138
+ nr_of_available_languages * all.size == translation_class.all.size
139
+ end
140
+
141
+ # ----------------------
142
+ # instance level API
143
+ # ----------------------
144
+
145
+ # list all available languages for this instance
146
+ def available_languages
147
+ Language.all :id => translations.map { |t| t.language_id }.uniq
148
+ end
149
+
150
+ # the number of all available languages for this instance
151
+ def nr_of_available_languages
152
+ available_languages.size
153
+ end
154
+
155
+ # checks if this instance is translated into all available languages for this model
156
+ def translations_complete?
157
+ self.class.nr_of_available_languages == translations.size
158
+ end
159
+
160
+
161
+ # TODO
162
+ # more API to support common usecases (and i18n/l10n solutions)
163
+
164
+ end
165
+ </code>
166
+ </pre>
167
+
168
+ h3. Inspired by (thx guys!)
169
+
170
+ * Neil Barnwell's comment on the top voted answer to "Schema for a multilanguage database":http://stackoverflow.com/questions/316780/schema-for-a-multilanguage-database
171
+
172
+ * Gabi Solomon's option (4) at this blog post on "Multilanguage database design approach":http://www.gsdesign.ro/blog/multilanguage-database-design-approach/
173
+
174
+
175
+ h3. Copyright
176
+
177
+ Copyright (c) 2009 Martin Gamsjaeger (snusnu). See "LICENSE":http://github.com/snusnu/dm-is-localizable/tree/master/LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,77 @@
1
+ require 'pathname'
2
+ require 'rake'
3
+
4
+ ROOT = Pathname(__FILE__).dirname.expand_path
5
+ JRUBY = RUBY_PLATFORM =~ /java/
6
+
7
+ begin
8
+ require 'jeweler'
9
+ Jeweler::Tasks.new do |gem|
10
+ gem.name = "dm-is-localizable"
11
+ gem.summary = %Q{Datamapper support for localization of content in multilanguage applications}
12
+ gem.email = "gamsnjaga@gmail.com"
13
+ gem.homepage = "http://github.com/snusnu/dm-is-localizable"
14
+ gem.authors = ["Martin Gamsjaeger (snusnu)"]
15
+ gem.add_dependency('dm-core', '>= 0.9.11')
16
+ gem.add_dependency('dm-is-remixable', '>= 0.9.11')
17
+ gem.add_dependency('dm-validations', '>= 0.9.11')
18
+ end
19
+
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
22
+ end
23
+
24
+ begin
25
+ gem 'rspec', '>=1.1.12'
26
+ require 'spec'
27
+ require 'spec/rake/spectask'
28
+
29
+ task :default => [ :spec ]
30
+
31
+ desc 'Run specifications'
32
+ Spec::Rake::SpecTask.new(:spec) do |t|
33
+ t.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
34
+ t.spec_files = Pathname.glob((ROOT + 'spec/**/*_spec.rb').to_s).map { |f| f.to_s }
35
+
36
+ begin
37
+ gem 'rcov', '~>0.8'
38
+ t.rcov = JRUBY ? false : (ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true)
39
+ t.rcov_opts << '--exclude' << 'spec'
40
+ t.rcov_opts << '--text-summary'
41
+ t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
42
+ rescue LoadError
43
+ # rcov not installed
44
+ end
45
+ end
46
+ rescue LoadError
47
+ # rspec not installed
48
+ end
49
+
50
+ begin
51
+ require 'cucumber/rake/task'
52
+ Cucumber::Rake::Task.new(:features)
53
+ rescue LoadError
54
+ task :features do
55
+ abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
56
+ end
57
+ end
58
+
59
+ task :default => :spec
60
+
61
+ require 'rake/rdoctask'
62
+ Rake::RDocTask.new do |rdoc|
63
+ if File.exist?('VERSION.yml')
64
+ config = YAML.load(File.read('VERSION.yml'))
65
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
66
+ else
67
+ version = ""
68
+ end
69
+
70
+ rdoc.rdoc_dir = 'rdoc'
71
+ rdoc.title = "dm-is-localizable #{version}"
72
+ rdoc.rdoc_files.include('README*')
73
+ rdoc.rdoc_files.include('lib/**/*.rb')
74
+ end
75
+
76
+ # require all tasks below tasks
77
+ Pathname.glob(ROOT.join('tasks/**/*.rb').to_s).each { |f| require f }