babilu 0.2.2

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.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 [name of plugin creator]
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,31 @@
1
+ Babilu
2
+ =======
3
+
4
+ Babilu converts all your translations into JavaScript so you can use them on
5
+ the client side. It mimicks the Ruby/Rails I18n API and works in pretty much the
6
+ same way:
7
+
8
+ //JavaScript
9
+ I18n.defaultLocale // "en"
10
+ I18n.locale // Whatever the locale has been set to on the server
11
+
12
+ I18n.t('hello') // "Hello World"
13
+ I18n.t('messages.invalid', {scope:['activerecord', 'errors']}) // "is invalid"
14
+ I18n.t('activerecord.errors.template.header', {count:4, model:'pony'}) // "4 errors prohibited this pony from being saved"
15
+
16
+ I18n.translations.en.ponies = {one: 'I have a pony', other: 'I have %{count} ponies'};
17
+ I18n.t('ponies', {count:5}) // "I have 5 ponies"
18
+
19
+ The only difference is that because JavaScript doesn't have symbols we can't
20
+ easily differentiate between keys and values in the "defaultValue" option. A workaround
21
+ is used in which strings starting with ":" are considered to be keys and are used for
22
+ looking up additional translations:
23
+
24
+ I18n.t('doesntexist', {defaultValue:'humbaba'}) // "humbaba"
25
+ I18n.t('doesntexist', {defaultValue:':hello'}) // "Hello world"
26
+ I18n.t('doesntexist', {defaultValue:[':alsodoesntexist', 'The Sasqutch: Fact or Fiction?']}) // "The Sasquatch: Fact or Fiction?"
27
+
28
+ This plugin depends on http://github.com/toretore/lucy
29
+
30
+
31
+ Copyright (c) 2008 Tore Darell, released under the MIT license
@@ -0,0 +1,38 @@
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 Babilu plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the Babilu plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'Babilu'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
24
+
25
+ require 'jeweler'
26
+ Jeweler::Tasks.new do |gem|
27
+ # gem is a Gem::Specification. See http://docs.rubygems.org/read/chapter/20 for more options
28
+ gem.name = "babilu"
29
+ gem.homepage = "http://github.com/toretore/babilu"
30
+ gem.license = "MIT"
31
+ gem.summary = %Q{Rails plugin for javascript i18n}
32
+ gem.description = %Q{Babilu converts all your translations into JavaScript so you can use them on the client side. It mimicks the Ruby/Rails I18n API and works in pretty much the same way}
33
+ gem.email = ""
34
+ gem.authors = ["Tore Darell"]
35
+ gem.add_runtime_dependency 'lucy'
36
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
37
+ end
38
+ Jeweler::RubygemsDotOrgTasks.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.2
data/init.rb ADDED
@@ -0,0 +1,3 @@
1
+ require "babilu"
2
+ I18n.reload!
3
+ Babilu.generate
@@ -0,0 +1,57 @@
1
+ require "lucy"
2
+ require "i18n_extensions"
3
+ module Babilu
4
+
5
+ JAVASCRIPT = File.read(File.join(File.dirname(__FILE__), 'javascripts', 'babilu.js'))
6
+
7
+ def self.generate
8
+ Lucy.generate("locales") do |g|
9
+ g.namespace = "I18n"
10
+ g[:defaultLocale] = default_locale
11
+ g[:translations] = translations
12
+ g << methods
13
+ end
14
+ end
15
+
16
+ def self.translations
17
+ I18n.all_translations
18
+ end
19
+
20
+ def self.default_locale
21
+ I18n.default_locale
22
+ end
23
+
24
+ def self.methods
25
+ JAVASCRIPT
26
+ end
27
+
28
+
29
+ module ControllerMethods
30
+
31
+ def self.included(controller)
32
+ controller.send(:after_filter, :set_locale_cookie)
33
+ controller.send(:after_filter, :generate_locale_javascript) if Rails.env.development?
34
+ end
35
+
36
+ private
37
+
38
+ def set_locale_cookie
39
+ cookies[:locale] = I18n.locale.to_s
40
+ end
41
+
42
+ #In development mode, re-generate locale data on each request
43
+ def generate_locale_javascript
44
+ Babilu.generate
45
+ end
46
+
47
+ end
48
+
49
+ class Railtie < Rails::Railtie
50
+ config.before_configuration do
51
+ config.action_view.javascript_expansions[:defaults] ||= [] << 'locales'
52
+ end
53
+ end if defined?(Rails::Railtie)
54
+
55
+ end
56
+
57
+ ActionController::Base.send(:include, Babilu::ControllerMethods)
@@ -0,0 +1,16 @@
1
+ module I18n
2
+ class << self
3
+ def all_translations
4
+ backend.all_translations
5
+ end
6
+ end
7
+
8
+ module Backend
9
+ class Simple
10
+ def all_translations
11
+ send(:init_translations) unless initialized?
12
+ translations
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,96 @@
1
+ (function(){
2
+
3
+ var interpolatePattern = /%\{([^}]+)\}/g;
4
+
5
+ //Replace %{foo} with obj.foo
6
+ function interpolate(str, obj){
7
+ return str.replace(interpolatePattern, function(){
8
+ return typeof obj[arguments[1]] == 'undefined' ? arguments[0] : obj[arguments[1]];
9
+ });
10
+ };
11
+
12
+ //Split "foo.bar" to ["foo", "bar"] if key is a string
13
+ function keyToArray(key){
14
+ if (!key) return [];
15
+ if (typeof key != "string") return key;
16
+ return key.split('.');
17
+ };
18
+
19
+ function locale(){
20
+ return I18n.locale || I18n.defaultLocale;
21
+ };
22
+
23
+ function getLocaleFromCookie(){
24
+ var cookies = document.cookie.split(/\s*;\s*/),
25
+ i, pair, locale;
26
+ for (i = 0; i < cookies.length; i++) {
27
+ pair = cookies[i].split('=');
28
+ if (pair[0] === 'locale') { locale = pair[1]; break; }
29
+ }
30
+ return locale;
31
+ };
32
+
33
+
34
+ I18n.init = function(){
35
+ this.locale = getLocaleFromCookie();
36
+ };
37
+
38
+ //Works mostly the same as the Ruby equivalent, except there are
39
+ //no symbols in JavaScript, so keys are always strings. The only time
40
+ //this makes a difference is when differentiating between keys and values
41
+ //in the defaultValue option. Strings starting with ":" will be considered
42
+ //to be keys and used for lookup, while other strings are returned as-is.
43
+ I18n.translate = function(key, opts){
44
+ if (typeof key != "string") { //Bulk lookup
45
+ var a = [], i;
46
+ for (i=0; i<key.length; i++) {
47
+ a.push(this.translate(key[i], opts));
48
+ }
49
+ return a;
50
+ } else {
51
+ opts = opts || {};
52
+ opts.defaultValue = opts.defaultValue || null;
53
+ key = keyToArray(opts.scope).concat(keyToArray(key));
54
+ var value = this.lookup(key, opts.defaultValue);
55
+ if (typeof value != "string" && value) value = this.pluralize(value, opts.count);
56
+ if (typeof value == "string") value = interpolate(value, opts);
57
+ return value;
58
+ }
59
+ };
60
+
61
+ I18n.t = I18n.translate;
62
+
63
+ //Looks up a translation using an array of strings where the last
64
+ //is the key and any string before that define the scope. The current
65
+ //locale is always prepended and does not need to be provided. The second
66
+ //parameter is an array of strings used as defaults if the key can not be
67
+ //found. If a key starts with ":" it is used as a key for lookup.
68
+ //This method does not perform pluralization or interpolation.
69
+ I18n.lookup = function(keys, defaults){
70
+ var i = 0, value = this.translations[locale()];
71
+ defaults = typeof defaults == "string" ? [defaults] : (defaults || []);
72
+ while (keys[i]) {
73
+ value = value && value[keys[i]];
74
+ i++;
75
+ }
76
+ if (value){
77
+ return value;
78
+ } else {
79
+ if (defaults.length == 0) {
80
+ return null;
81
+ } else if (defaults[0].substr(0,1) == ':') {
82
+ return this.lookup(keys.slice(0,keys.length-1).concat(keyToArray(defaults[0].substr(1))), defaults.slice(1));
83
+ } else {
84
+ return defaults[0];
85
+ }
86
+ }
87
+ };
88
+
89
+ I18n.pluralize = function(value, count){
90
+ if (typeof count != 'number') return value;
91
+ return count == 1 ? value.one : value.other;
92
+ };
93
+
94
+ })();
95
+
96
+ I18n.init();
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :i18n_js do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,51 @@
1
+ require 'test/test_helper'
2
+ require 'babilu'
3
+
4
+ module SharedSetup
5
+
6
+ TRANSLATIONS = {
7
+ :en => {
8
+ :hello => "Hello World"
9
+ },
10
+ :no => {
11
+ :hello => "Hei verden"
12
+ }
13
+ }
14
+
15
+ def setup
16
+ I18n.load_path = []
17
+ I18n.backend = I18n::Backend::Simple.new
18
+ I18n.default_locale = :en
19
+ TRANSLATIONS.each{|l,t| I18n.backend.store_translations(l,t) }
20
+ end
21
+
22
+ end
23
+
24
+ class BabiluI18nExtensionsTest < Test::Unit::TestCase
25
+
26
+ include SharedSetup
27
+
28
+ def test_all_translations_should_be_defined_on_simple_backend
29
+ assert I18n::Backend::Simple.instance_methods.include?("all_translations")
30
+ end
31
+
32
+ def test_all_translations_should_return_a_hash_with_all_translations_in_all_locales
33
+ assert_equal TRANSLATIONS, I18n.all_translations
34
+ end
35
+
36
+ end
37
+
38
+
39
+ class BabiluTest < Test::Unit::TestCase
40
+
41
+ include SharedSetup
42
+
43
+ def test_translations_should_return_all_translations
44
+ assert_equal TRANSLATIONS, Babilu.translations
45
+ end
46
+
47
+ def test_default_locale_should_use_i18n_default_locale
48
+ assert_equal I18n.default_locale, Babilu.default_locale
49
+ end
50
+
51
+ end
@@ -0,0 +1,214 @@
1
+ @CHARSET "UTF-8";
2
+
3
+ /* --------------------
4
+ * @Layout
5
+ */
6
+
7
+ html {
8
+ overflow: hidden;
9
+ }
10
+
11
+ body, #jsspec_container {
12
+ overflow: hidden;
13
+ padding: 0;
14
+ margin: 0;
15
+ width: 100%;
16
+ height: 100%;
17
+ }
18
+
19
+ #title {
20
+ padding: 0;
21
+ margin: 0;
22
+ position: absolute;
23
+ top: 0px;
24
+ left: 0px;
25
+ width: 100%;
26
+ height: 40px;
27
+ overflow: hidden;
28
+ }
29
+
30
+ #list {
31
+ padding: 0;
32
+ margin: 0;
33
+ position: absolute;
34
+ top: 40px;
35
+ left: 0px;
36
+ bottom: 0px;
37
+ overflow: auto;
38
+ width: 250px;
39
+ _height:expression(document.body.clientHeight-40);
40
+ }
41
+
42
+ #log {
43
+ padding: 0;
44
+ margin: 0;
45
+ position: absolute;
46
+ top: 40px;
47
+ left: 250px;
48
+ right: 0px;
49
+ bottom: 0px;
50
+ overflow: auto;
51
+ _height:expression(document.body.clientHeight-40);
52
+ _width:expression(document.body.clientWidth-250);
53
+ }
54
+
55
+
56
+
57
+ /* --------------------
58
+ * @Decorations and colors
59
+ */
60
+ * {
61
+ padding: 0;
62
+ margin: 0;
63
+ font-family: "Lucida Grande", Helvetica, sans-serif;
64
+ }
65
+
66
+ li {
67
+ list-style: none;
68
+ }
69
+
70
+ /* hiding subtitles */
71
+ h2 {
72
+ display: none;
73
+ }
74
+
75
+ /* title section */
76
+ div#title {
77
+ padding: 0em 0.5em;
78
+ }
79
+
80
+ div#title h1 {
81
+ font-size: 1.5em;
82
+ float: left;
83
+ }
84
+
85
+ div#title ul li {
86
+ float: left;
87
+ padding: 0.5em 0em 0.5em 0.75em;
88
+ }
89
+
90
+ div#title p {
91
+ float:right;
92
+ margin-right:1em;
93
+ font-size: 0.75em;
94
+ }
95
+
96
+ /* spec container */
97
+ ul.specs {
98
+ margin: 0.5em;
99
+ }
100
+ ul.specs li {
101
+ margin-bottom: 0.1em;
102
+ }
103
+
104
+ /* spec title */
105
+ ul.specs li h3 {
106
+ font-weight: bold;
107
+ font-size: 0.75em;
108
+ padding: 0.2em 1em;
109
+ }
110
+
111
+ /* example container */
112
+ ul.examples li {
113
+ border-style: solid;
114
+ border-width: 0px 0px 1px 5px;
115
+ margin: 0.2em 0em 0.2em 1em;
116
+ }
117
+
118
+ /* example title */
119
+ ul.examples li h4 {
120
+ font-weight: normal;
121
+ font-size: 0.75em;
122
+ margin-left: 1em;
123
+ }
124
+
125
+ /* example explaination */
126
+ ul.examples li div {
127
+ padding: 1em 2em;
128
+ font-size: 0.75em;
129
+ }
130
+
131
+ /* styles for ongoing, success, failure, error */
132
+ div.success, div.success a {
133
+ color: #FFFFFF;
134
+ background-color: #65C400;
135
+ }
136
+
137
+ ul.specs li.success h3, ul.specs li.success h3 a {
138
+ color: #FFFFFF;
139
+ background-color: #65C400;
140
+ }
141
+
142
+ ul.examples li.success, ul.examples li.success a {
143
+ color: #3D7700;
144
+ background-color: #DBFFB4;
145
+ border-color: #65C400;
146
+ }
147
+
148
+ div.exception, div.exception a {
149
+ color: #FFFFFF;
150
+ background-color: #C20000;
151
+ }
152
+
153
+ ul.specs li.exception h3, ul.specs li.exception h3 a {
154
+ color: #FFFFFF;
155
+ background-color: #C20000;
156
+ }
157
+
158
+ ul.examples li.exception, ul.examples li.exception a {
159
+ color: #C20000;
160
+ background-color: #FFFBD3;
161
+ border-color: #C20000;
162
+ }
163
+
164
+ div.ongoing, div.ongoing a {
165
+ color: #000000;
166
+ background-color: #FFFF80;
167
+ }
168
+
169
+ ul.specs li.ongoing h3, ul.specs li.ongoing h3 a {
170
+ color: #000000;
171
+ background-color: #FFFF80;
172
+ }
173
+
174
+ ul.examples li.ongoing, ul.examples li.ongoing a {
175
+ color: #000000;
176
+ background-color: #FFFF80;
177
+ border-color: #DDDD00;
178
+ }
179
+
180
+
181
+
182
+ /* --------------------
183
+ * values
184
+ */
185
+ .number_value, .string_value, .regexp_value, .boolean_value, .dom_value {
186
+ font-family: monospace;
187
+ color: blue;
188
+ }
189
+ .object_value, .array_value {
190
+ line-height: 2em;
191
+ padding: 0.1em 0.2em;
192
+ margin: 0.1em 0;
193
+ }
194
+ .date_value {
195
+ font-family: monospace;
196
+ color: olive;
197
+ }
198
+ .undefined_value, .null_value {
199
+ font-style: italic;
200
+ color: blue;
201
+ }
202
+ .dom_attr_name {
203
+ }
204
+ .dom_attr_value {
205
+ color: red;
206
+ }
207
+ .dom_path {
208
+ font-size: 0.75em;
209
+ color: gray;
210
+ }
211
+ strong {
212
+ font-weight: normal;
213
+ background-color: #FFC6C6;
214
+ }