localite 0.1
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/Manifest +0 -0
- data/Rakefile +15 -0
- data/VERSION +1 -0
- data/config/dependencies.rb +5 -0
- data/config/gem.yml +7 -0
- data/init.rb +11 -0
- data/lib/localite.rb +204 -0
- data/lib/localite/rails_filter.rb +35 -0
- data/lib/localite/scope.rb +140 -0
- data/lib/localite/settings.rb +37 -0
- data/lib/localite/template.rb +126 -0
- data/lib/localite/translate.rb +65 -0
- data/localite.gemspec +33 -0
- data/localite.tmproj +27 -0
- data/script/console +21 -0
- data/script/rebuild +7 -0
- data/tasks/echoe.rake +48 -0
- data/test/i18n/de.yml +15 -0
- data/test/initializers/fake_rails.rb +20 -0
- data/test/test.rb +30 -0
- metadata +101 -0
data/Manifest
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
task :default => :test
|
2
|
+
|
3
|
+
task :test do
|
4
|
+
sh "ruby test/test.rb"
|
5
|
+
end
|
6
|
+
|
7
|
+
task :rcov do
|
8
|
+
sh "cd test; rcov -o ../coverage -x ruby/.*/gems -x ^test.rb test.rb"
|
9
|
+
end
|
10
|
+
|
11
|
+
task :rdoc do
|
12
|
+
sh "rdoc -o doc/rdoc"
|
13
|
+
end
|
14
|
+
|
15
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1
|
data/config/gem.yml
ADDED
data/init.rb
ADDED
data/lib/localite.rb
ADDED
@@ -0,0 +1,204 @@
|
|
1
|
+
require "logger"
|
2
|
+
|
3
|
+
#
|
4
|
+
# This is a *really* simple template and translation engine.
|
5
|
+
#
|
6
|
+
# TODO: Use erubis instead of this simple engine...
|
7
|
+
|
8
|
+
module Localite; end
|
9
|
+
|
10
|
+
file_dir = File.expand_path(File.dirname(__FILE__))
|
11
|
+
|
12
|
+
# require "#{file_dir}/localite/missing_translation"
|
13
|
+
require "#{file_dir}/localite/scope"
|
14
|
+
require "#{file_dir}/localite/settings"
|
15
|
+
require "#{file_dir}/localite/translate"
|
16
|
+
require "#{file_dir}/localite/template"
|
17
|
+
|
18
|
+
module Localite
|
19
|
+
#
|
20
|
+
# Add the Localite adapters for Strings ad Symbols.
|
21
|
+
def self.init
|
22
|
+
String.send :include, StringAdapter
|
23
|
+
Symbol.send :include, SymbolAdapter
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# a logger
|
28
|
+
def self.logger
|
29
|
+
klass = defined?(ActiveSupport) ? ActiveSupport::BufferedLogger : Logger
|
30
|
+
|
31
|
+
@logger ||= klass.new("log/localite.log")
|
32
|
+
end
|
33
|
+
|
34
|
+
extend Settings
|
35
|
+
extend Translate
|
36
|
+
extend Scope
|
37
|
+
|
38
|
+
public
|
39
|
+
|
40
|
+
#
|
41
|
+
# Translating a string:
|
42
|
+
#
|
43
|
+
# If no translation is found we try to translate the string in the base
|
44
|
+
# language. If there is no base language translation we return the
|
45
|
+
# string, assuming a base language string.
|
46
|
+
module StringAdapter
|
47
|
+
def t(*args)
|
48
|
+
translated = Localite.translate(self, :no_raise) || self
|
49
|
+
Localite.template translated, *args
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Translating a string:
|
55
|
+
#
|
56
|
+
# If no translation is found we try to translate the string in the base
|
57
|
+
# language. If there is no base language translation we raise areturn the
|
58
|
+
# string, assuming a base language string.
|
59
|
+
module SymbolAdapter
|
60
|
+
def t(*args)
|
61
|
+
translated = Localite.translate(self, :do_raise)
|
62
|
+
Localite.template translated, *args
|
63
|
+
end
|
64
|
+
|
65
|
+
# returns nil, if there is no translation.
|
66
|
+
def t?(*args)
|
67
|
+
translated = Localite.translate(self, :no_raise)
|
68
|
+
Localite.template translated, *args if translated
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.template(template, *args)
|
73
|
+
Template.run mode, template, *args
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
module Localite::Etest
|
78
|
+
|
79
|
+
#
|
80
|
+
# make sure .t actually runs the Template engine
|
81
|
+
def test_tmpl
|
82
|
+
assert_equal "xyz", "xyz".t(:xyz => "abc")
|
83
|
+
assert_equal "abc", "{*xyz*}".t(:xyz => "abc")
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_base_lookup
|
87
|
+
assert !I18n.load_path.empty?
|
88
|
+
|
89
|
+
assert_equal("en.t", "t".t)
|
90
|
+
Localite.in("en") {
|
91
|
+
assert_equal("en.t", "t".t )
|
92
|
+
}
|
93
|
+
|
94
|
+
Localite.in("de") {
|
95
|
+
assert_equal("de.t", "t".t )
|
96
|
+
}
|
97
|
+
|
98
|
+
assert_equal("de.t", Localite.in("de") { "t".t })
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_lookup_de
|
102
|
+
Localite.in("de") do
|
103
|
+
# flat translation
|
104
|
+
assert_equal "de.t", "t".t
|
105
|
+
|
106
|
+
Localite.scope(:outer, :inner) do
|
107
|
+
assert_equal("de/outer/inner/x1", "x1".t)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Miss "x1", and don't translate missing entries
|
111
|
+
assert_equal("x1", "x1".t)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_lookup_in_base
|
116
|
+
Localite.in("en") do
|
117
|
+
# lookup "base" in base translation
|
118
|
+
assert_equal "en_only", "base".t
|
119
|
+
end
|
120
|
+
|
121
|
+
Localite.in("de") do
|
122
|
+
# lookup "base" in base (i.e. en) translation
|
123
|
+
assert_equal "en_only", "base".t
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_lookup_en
|
128
|
+
Localite.in("en") do
|
129
|
+
|
130
|
+
# flat translation
|
131
|
+
assert_equal "en.t", "t".t
|
132
|
+
|
133
|
+
Localite.scope(:outer, :inner, :x1) do
|
134
|
+
assert_equal("en/outer/inner/x1", "x1".t)
|
135
|
+
end
|
136
|
+
|
137
|
+
# Miss "x1", and don't translate missing entries
|
138
|
+
assert_equal("x1", "x1".t)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_lookup_no_specific_lang
|
143
|
+
# flat translation
|
144
|
+
assert_equal "en.t", "t".t
|
145
|
+
|
146
|
+
Localite.scope(:outer, :inner, :x1) do
|
147
|
+
assert_equal("en/outer/inner/x1", "x1".t)
|
148
|
+
end
|
149
|
+
|
150
|
+
# Miss "x1", and don't translate missing entries
|
151
|
+
assert_equal("x1", "x1".t)
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_lookup_symbols
|
155
|
+
assert :base.t?
|
156
|
+
|
157
|
+
assert_equal "en_only", :base.t
|
158
|
+
|
159
|
+
Localite.in("en") do
|
160
|
+
assert_equal "en_only", :base.t
|
161
|
+
end
|
162
|
+
|
163
|
+
Localite.in("de") do
|
164
|
+
assert_equal "en_only", :base.t
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_missing_lookup_symbols
|
169
|
+
assert !:missing.t?
|
170
|
+
assert_raise(Localite::Translate::Missing) {
|
171
|
+
assert_equal "en_only", :missing.t
|
172
|
+
}
|
173
|
+
|
174
|
+
Localite.in("en") do
|
175
|
+
assert_raise(Localite::Translate::Missing) {
|
176
|
+
:missing.t
|
177
|
+
}
|
178
|
+
end
|
179
|
+
|
180
|
+
Localite.in("de") do
|
181
|
+
assert_raise(Localite::Translate::Missing) {
|
182
|
+
:missing.t
|
183
|
+
}
|
184
|
+
end
|
185
|
+
|
186
|
+
begin
|
187
|
+
:missing.t
|
188
|
+
rescue Localite::Translate::Missing
|
189
|
+
assert_kind_of(String, $!.to_s)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# def test_html
|
194
|
+
# assert_equal ">", "{*'>'*}".t(:xyz => [1, 2, 3], :fl => [1.0])
|
195
|
+
# assert_equal ">", "{*'>'*}".t(:html, :xyz => [1, 2, 3], :fl => [1.0])
|
196
|
+
# assert_equal "3 Fixnums > 1 Float", "{*pl xyz*} > {*pl fl*}".t(:xyz => [1, 2, 3], :fl => [1.0])
|
197
|
+
# assert_equal "3 Fixnums > 1 Float", "{*pl xyz*} > {*pl fl*}".t(:html, :xyz => [1, 2, 3], :fl => [1.0])
|
198
|
+
# end
|
199
|
+
#
|
200
|
+
# def test_tmpl
|
201
|
+
# # assert_equal "3 chars", "{*len*} chars".t(:len => 3)
|
202
|
+
# assert_equal "3 chars", "{*length*} chars".t(:length => 3)
|
203
|
+
# end
|
204
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Localite::RailsFilter
|
2
|
+
def self.filter(controller, &block)
|
3
|
+
#
|
4
|
+
# get the current locale
|
5
|
+
locale = begin
|
6
|
+
controller.send(:current_locale)
|
7
|
+
rescue NoMethodError
|
8
|
+
end
|
9
|
+
|
10
|
+
#
|
11
|
+
# get the current locale
|
12
|
+
begin
|
13
|
+
scope = controller.send(:localite_scope)
|
14
|
+
scope = [ scope ] if scope && !scope.is_a?(Array)
|
15
|
+
rescue NoMethodError
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# set up localite for this action.
|
20
|
+
Localite.html do
|
21
|
+
Localite.in(locale) do
|
22
|
+
Localite.scope(*scope, &block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
#
|
30
|
+
# override this method to adjust localite parameters
|
31
|
+
def current_locale
|
32
|
+
return params[:locale] if params[:locale] && params[:locale] =~ /^[a-z][a-z]$/
|
33
|
+
return params[:lang] if params[:lang] && params[:lang] =~ /^[a-z][a-z]$/
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
module Localite::Scope
|
2
|
+
#
|
3
|
+
# scope allows to set a scope around a translation. A scoped translation
|
4
|
+
#
|
5
|
+
# Localite.scope("scope") do
|
6
|
+
# "msg".t
|
7
|
+
# end
|
8
|
+
#
|
9
|
+
# will look up "scope.msg" and "msg", in that order, and return the first
|
10
|
+
# matching translation in the current locale. Scopes can be stacked; looking
|
11
|
+
# up a scoped translation
|
12
|
+
# Localite.scope("outer") do
|
13
|
+
# Localite.scope("scope") do
|
14
|
+
# "msg".t
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# will look up "outer.scope.msg", "scope.msg", "msg".
|
19
|
+
#
|
20
|
+
# If no translation will be found we look up the same entries in the base
|
21
|
+
# locale.
|
22
|
+
def scope(*args, &block)
|
23
|
+
return yield if args.empty?
|
24
|
+
|
25
|
+
scopes.exec(args.shift) do
|
26
|
+
scope *args, &block
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def scopes
|
31
|
+
Thread.current[:"localite:scopes"] ||= Scopes.new
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# The mode setting defines how the template engine deals with its
|
36
|
+
# parameters. In :html mode all parameters will be subject to HTML
|
37
|
+
# escaping, while in :text mode the parameters remain unchanged.
|
38
|
+
def html(&block)
|
39
|
+
in_mode :html, &block
|
40
|
+
end
|
41
|
+
|
42
|
+
def text(&block)
|
43
|
+
in_mode :text, &block
|
44
|
+
end
|
45
|
+
|
46
|
+
def mode
|
47
|
+
Thread.current[:"localite:mode"] || :text
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def in_mode(mode, &block)
|
53
|
+
old = Thread.current[:"localite:mode"]
|
54
|
+
Thread.current[:"localite:mode"] = mode
|
55
|
+
yield
|
56
|
+
ensure
|
57
|
+
Thread.current[:"localite:mode"] = old
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
class Scopes < Array
|
62
|
+
def exec(s, &block)
|
63
|
+
s = "#{last}.#{s}" if last
|
64
|
+
push s
|
65
|
+
|
66
|
+
yield
|
67
|
+
ensure
|
68
|
+
pop
|
69
|
+
end
|
70
|
+
|
71
|
+
def each(s)
|
72
|
+
reverse_each do |entry|
|
73
|
+
yield "#{entry}.#{s}"
|
74
|
+
end
|
75
|
+
|
76
|
+
yield s
|
77
|
+
end
|
78
|
+
|
79
|
+
def first(s)
|
80
|
+
each(s) do |entry|
|
81
|
+
return entry
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
module Localite::Scope::Etest
|
88
|
+
Scopes = Localite::Scope::Scopes
|
89
|
+
|
90
|
+
def test_scope
|
91
|
+
scope = Scopes.new
|
92
|
+
scope.exec("a") do
|
93
|
+
scope.exec("b") do
|
94
|
+
scope.exec("b") do
|
95
|
+
r = []
|
96
|
+
scope.each("str") do |scoped|
|
97
|
+
r << scoped
|
98
|
+
end
|
99
|
+
assert_equal %w(a.b.b.str a.b.str a.str str), r
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_more_scopes
|
106
|
+
Localite.scope("a", :b, "b") do
|
107
|
+
r = []
|
108
|
+
Localite.scopes.each("str") do |scoped|
|
109
|
+
r << scoped
|
110
|
+
end
|
111
|
+
assert_equal %w(a.b.b.str a.b.str a.str str), r
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_more_scopes_w_dots
|
116
|
+
Localite.scope("a", :b, "b.c.d") do
|
117
|
+
r = []
|
118
|
+
Localite.scopes.each("str.y") do |scoped|
|
119
|
+
r << scoped
|
120
|
+
end
|
121
|
+
assert_equal %w(a.b.b.c.d.str.y a.b.str.y a.str.y str.y), r
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_empty_scopes
|
126
|
+
r = []
|
127
|
+
Localite.scopes.each("str.y") do |scoped|
|
128
|
+
r << scoped
|
129
|
+
end
|
130
|
+
assert_equal %w(str.y), r
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_modi
|
134
|
+
assert_equal "abc", "param".t(:xxx => "abc")
|
135
|
+
assert_equal "a > c", "param".t(:xxx => "a > c")
|
136
|
+
assert_equal "a > c", Localite.text { "param".t(:xxx => "a > c") }
|
137
|
+
assert_equal "a > c", Localite.html { "param".t(:xxx => "a > c") }
|
138
|
+
assert_equal "a > c", "param".t(:xxx => "a > c")
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Localite::Settings
|
2
|
+
#
|
3
|
+
# Returns the base locale; e.g. :en
|
4
|
+
def base
|
5
|
+
I18n.default_locale
|
6
|
+
end
|
7
|
+
|
8
|
+
#
|
9
|
+
# returns the current locale; defaults to the base locale
|
10
|
+
def locale
|
11
|
+
@locale || base
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
# is a specific locale available?
|
16
|
+
def available?(locale)
|
17
|
+
locale && I18n.backend.available_locales.include?(locale.to_sym)
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# sets the current locale. If the locale is not available it changes
|
22
|
+
# the locale to the default locale.
|
23
|
+
def locale=(locale)
|
24
|
+
locale = locale.to_sym
|
25
|
+
@locale = available?(locale) ? locale : base
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# runs a block in the changed locale
|
30
|
+
def in(locale, &block)
|
31
|
+
old = self.locale
|
32
|
+
self.locale = locale if locale
|
33
|
+
yield
|
34
|
+
ensure
|
35
|
+
self.locale = old
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require "cgi"
|
2
|
+
|
3
|
+
class Localite::Template < String
|
4
|
+
def self.run(mode, template, opts = {})
|
5
|
+
new(template).run(mode, opts)
|
6
|
+
end
|
7
|
+
|
8
|
+
#
|
9
|
+
# the environment during run
|
10
|
+
class Env
|
11
|
+
module Helpers
|
12
|
+
# def html(s)
|
13
|
+
# CGI.escapeHTML s
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# def hi(s)
|
17
|
+
# "“" + CGI.escapeHTML(s) + "”"
|
18
|
+
# end
|
19
|
+
|
20
|
+
#
|
21
|
+
# pluralize something and add count
|
22
|
+
# pl("apple", 1) -> "1 apple"
|
23
|
+
# pl("apple", 2) -> "2 apples"
|
24
|
+
#
|
25
|
+
# Note a special case on arrays:
|
26
|
+
# pl(%w(apple peach cherry)) -> "3 Strings"
|
27
|
+
def pl(name, count=nil)
|
28
|
+
if count
|
29
|
+
"#{count} #{count != 1 ? name.pluralize : name.singularize}"
|
30
|
+
elsif name.respond_to?(:first) && !name.is_a?(String)
|
31
|
+
pl name.first.class.name, name.length # special case, see above.
|
32
|
+
else
|
33
|
+
name.pluralize
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def method_missing(sym, *args, &block)
|
39
|
+
begin
|
40
|
+
return @host.fetch(sym.to_sym)
|
41
|
+
rescue IndexError
|
42
|
+
:void
|
43
|
+
end
|
44
|
+
|
45
|
+
begin
|
46
|
+
return @host.fetch(sym.to_s)
|
47
|
+
rescue IndexError
|
48
|
+
:void
|
49
|
+
end
|
50
|
+
|
51
|
+
super
|
52
|
+
end
|
53
|
+
|
54
|
+
def initialize(host)
|
55
|
+
@host = host
|
56
|
+
extend Helpers
|
57
|
+
end
|
58
|
+
|
59
|
+
def [](code)
|
60
|
+
eval(code).to_s
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def run(mode, opts = {})
|
65
|
+
#
|
66
|
+
env = Env.new(opts)
|
67
|
+
|
68
|
+
#
|
69
|
+
# get all --> {* code *} <-- parts from the template strings and send
|
70
|
+
# them thru the environment.
|
71
|
+
gsub(/\{\*([^\}]+?)\*\}/) do |_|
|
72
|
+
Modi.send mode, env[$1]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
module Modi
|
77
|
+
def self.text(s); s; end
|
78
|
+
def self.html(s); CGI.escapeHTML(s); end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
module Localite::Template::Etest
|
83
|
+
Template = Localite::Template
|
84
|
+
|
85
|
+
def test_templates
|
86
|
+
assert_equal "abc", Template.run(:text, "{*xyz*}", :xyz => "abc")
|
87
|
+
assert_equal "3 items", Template.run(:text, "{*pl 'item', xyz.length*}", :xyz => "abc")
|
88
|
+
assert_equal "xyz", Template.run(:text, "xyz", :xyz => "abc")
|
89
|
+
assert_equal "abc", Template.run(:text, "{*xyz*}", :xyz => "abc")
|
90
|
+
assert_equal "3", Template.run(:text, "{*xyz.length*}", :xyz => "abc")
|
91
|
+
assert_equal "3", Template.run(:text, "{*xyz.length*}", :xyz => "abc")
|
92
|
+
assert_equal "3 Fixnums", Template.run(:text, "{*pl xyz*}", :xyz => [1, 2, 3])
|
93
|
+
assert_equal "3 Fixnums and 1 Float", Template.run(:text, "{*pl xyz*} and {*pl fl*}", :xyz => [1, 2, 3], :fl => [1.0])
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_pl
|
97
|
+
h = Object.new.extend(Localite::Template::Env::Helpers)
|
98
|
+
assert_equal "1 apple", h.pl("apple", 1)
|
99
|
+
assert_equal "2 apples", h.pl("apple", 2)
|
100
|
+
assert_equal "1 apple", h.pl("apples", 1)
|
101
|
+
assert_equal "2 apples", h.pl("apples", 2)
|
102
|
+
|
103
|
+
assert_equal "apples", h.pl("apples")
|
104
|
+
assert_equal "apples", h.pl("apple")
|
105
|
+
|
106
|
+
assert_equal "3 Strings", h.pl(%w(apple peach cherry))
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_html_env
|
110
|
+
assert_equal "a>c", Template.run(:text, "{*xyz*}", :xyz => "a>c")
|
111
|
+
assert_equal "a>c", Template.run(:html, "{*xyz*}", :xyz => "a>c")
|
112
|
+
assert_equal "> a>c", Template.run(:text, "> {*xyz*}", :xyz => "a>c")
|
113
|
+
assert_equal "> a>c", Template.run(:html, "> {*xyz*}", :xyz => "a>c")
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_template_hash
|
117
|
+
assert_equal "a>c", Template.run(:text, "{*xyz*}", :xyz => "a>c")
|
118
|
+
assert_equal "a>c", Template.run(:text, "{*xyz*}", "xyz" => "a>c")
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_template_hash_missing
|
122
|
+
assert_raise(NameError) {
|
123
|
+
Template.run(:text, "{*abc*}", :xyz => "a>c")
|
124
|
+
}
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "set"
|
2
|
+
|
3
|
+
module Localite::Translate
|
4
|
+
#
|
5
|
+
# translate a string
|
6
|
+
#
|
7
|
+
# returns the translated string in the current locale.
|
8
|
+
# If no translation is found try the base locale.
|
9
|
+
# If still no translation is found, return nil
|
10
|
+
#
|
11
|
+
def translate(s, raise_mode)
|
12
|
+
r = do_translate(locale, s)
|
13
|
+
return r if r
|
14
|
+
|
15
|
+
r = do_translate(base, s) if base != locale
|
16
|
+
return r if r
|
17
|
+
|
18
|
+
raise Missing, [locale, s] if raise_mode != :no_raise
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def do_translate(locale, s)
|
24
|
+
scopes.each(s) do |scoped_string|
|
25
|
+
tr = Localite::Translate.translate_via_i18n locale, scoped_string
|
26
|
+
return tr if tr
|
27
|
+
end
|
28
|
+
|
29
|
+
record_missing locale, scopes.first(s)
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.translate_via_i18n(locale, s)
|
34
|
+
locale = base unless I18n.backend.available_locales.include?(locale)
|
35
|
+
I18n.locale = locale
|
36
|
+
I18n.translate(s, :raise => true)
|
37
|
+
rescue I18n::MissingTranslationData
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# log a missing translation and raise an exception
|
43
|
+
def record_missing(locale, s)
|
44
|
+
@missing_translations ||= Set.new
|
45
|
+
entry = [ locale, s ]
|
46
|
+
return if @missing_translations.include?(entry)
|
47
|
+
@missing_translations << entry
|
48
|
+
logger.warn "Missing translation: [#{locale}] #{s.inspect}"
|
49
|
+
end
|
50
|
+
|
51
|
+
public
|
52
|
+
|
53
|
+
class Missing < RuntimeError
|
54
|
+
attr :locale
|
55
|
+
attr :string
|
56
|
+
|
57
|
+
def initialize(opts)
|
58
|
+
@locale, @string = *opts
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s
|
62
|
+
"Missing translation: [#{locale}] #{string.inspect}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/localite.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{localite}
|
5
|
+
s.version = "0.1"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["pboy"]
|
9
|
+
s.date = %q{2010-05-11}
|
10
|
+
s.description = %q{An easy to use localization gem.}
|
11
|
+
s.email = %q{eno-pboy@open-lab.org}
|
12
|
+
s.extra_rdoc_files = ["lib/localite.rb", "lib/localite/rails_filter.rb", "lib/localite/scope.rb", "lib/localite/settings.rb", "lib/localite/template.rb", "lib/localite/translate.rb", "tasks/echoe.rake"]
|
13
|
+
s.files = ["Manifest", "Rakefile", "VERSION", "config/dependencies.rb", "config/gem.yml", "init.rb", "lib/localite.rb", "lib/localite/rails_filter.rb", "lib/localite/scope.rb", "lib/localite/settings.rb", "lib/localite/template.rb", "lib/localite/translate.rb", "localite.tmproj", "script/console", "script/rebuild", "tasks/echoe.rake", "test/i18n/de.yml", "test/initializers/fake_rails.rb", "test/test.rb", "localite.gemspec"]
|
14
|
+
s.homepage = %q{http://github.com/pboy/localite}
|
15
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Localite"]
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.rubyforge_project = %q{localite}
|
18
|
+
s.rubygems_version = %q{1.3.6}
|
19
|
+
s.summary = %q{An easy to use localization gem.}
|
20
|
+
|
21
|
+
if s.respond_to? :specification_version then
|
22
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
23
|
+
s.specification_version = 3
|
24
|
+
|
25
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
26
|
+
s.add_runtime_dependency(%q<i18n>, [">= 0"])
|
27
|
+
else
|
28
|
+
s.add_dependency(%q<i18n>, [">= 0"])
|
29
|
+
end
|
30
|
+
else
|
31
|
+
s.add_dependency(%q<i18n>, [">= 0"])
|
32
|
+
end
|
33
|
+
end
|
data/localite.tmproj
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>documents</key>
|
6
|
+
<array>
|
7
|
+
<dict>
|
8
|
+
<key>expanded</key>
|
9
|
+
<true/>
|
10
|
+
<key>name</key>
|
11
|
+
<string>localite</string>
|
12
|
+
<key>regexFolderFilter</key>
|
13
|
+
<string>!.*/(\.[^/]*|CVS|localite|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
|
14
|
+
<key>sourceDirectory</key>
|
15
|
+
<string></string>
|
16
|
+
</dict>
|
17
|
+
</array>
|
18
|
+
<key>fileHierarchyDrawerWidth</key>
|
19
|
+
<integer>339</integer>
|
20
|
+
<key>metaData</key>
|
21
|
+
<dict/>
|
22
|
+
<key>showFileHierarchyDrawer</key>
|
23
|
+
<true/>
|
24
|
+
<key>windowFrame</key>
|
25
|
+
<string>{{10, 0}, {924, 778}}</string>
|
26
|
+
</dict>
|
27
|
+
</plist>
|
data/script/console
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Start a console that initializes the gem
|
4
|
+
#
|
5
|
+
require "irb"
|
6
|
+
require "rubygems"
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'wirble'
|
10
|
+
Wirble.init
|
11
|
+
Wirble.colorize
|
12
|
+
rescue LoadError
|
13
|
+
STDERR.puts "To enable colorized and tab completed run 'gem install wirble'"
|
14
|
+
end
|
15
|
+
|
16
|
+
$: << "#{File.dirname(__FILE__)}/../lib"
|
17
|
+
load "#{File.dirname(__FILE__)}/../init.rb"
|
18
|
+
|
19
|
+
I18n.load_path += Dir["#{File.dirname(__FILE__)}/../test/i18n/*.yml"]
|
20
|
+
|
21
|
+
IRB.start
|
data/script/rebuild
ADDED
data/tasks/echoe.rake
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
#
|
2
|
+
# GEM settings
|
3
|
+
#
|
4
|
+
GEM_ROOT = File.expand_path("#{File.dirname(__FILE__)}/..")
|
5
|
+
|
6
|
+
if gem_config = YAML.load(File.read("#{GEM_ROOT}/config/gem.yml"))
|
7
|
+
require 'echoe'
|
8
|
+
|
9
|
+
#
|
10
|
+
# a dependency reader
|
11
|
+
module Dependency
|
12
|
+
@@dependencies = []
|
13
|
+
|
14
|
+
def self.require(file)
|
15
|
+
@@dependencies << file
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.load
|
19
|
+
eval File.read("#{GEM_ROOT}/config/dependencies.rb"), binding
|
20
|
+
@@dependencies
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Echoe.new(File.basename(GEM_ROOT), File.read("#{GEM_ROOT}/VERSION")) do |p|
|
25
|
+
gem_config.each do |k,v|
|
26
|
+
p.send "#{k}=",v
|
27
|
+
end
|
28
|
+
|
29
|
+
p.runtime_dependencies = Dependency.load
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "Rebuild and install the gem"
|
33
|
+
task :rebuild => %w(manifest default build_gemspec package) do
|
34
|
+
gem = Dir.glob("pkg/*.gem").sort_by do |filename|
|
35
|
+
File.new(filename).mtime
|
36
|
+
end.last
|
37
|
+
|
38
|
+
puts "============================================="
|
39
|
+
puts "Installing gem..."
|
40
|
+
|
41
|
+
system "gem install #{gem} > /dev/null 2>&1"
|
42
|
+
|
43
|
+
puts ""
|
44
|
+
puts "I built and installed the gem for you. To upload, run "
|
45
|
+
puts
|
46
|
+
puts " gem push #{gem}"
|
47
|
+
end
|
48
|
+
end
|
data/test/i18n/de.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#
|
2
|
+
# set up fake rails
|
3
|
+
|
4
|
+
require "active_record"
|
5
|
+
require "fileutils"
|
6
|
+
|
7
|
+
LOGFILE = "log/test.log"
|
8
|
+
SQLITE_FILE = ":memory:"
|
9
|
+
|
10
|
+
#
|
11
|
+
# -- set up fake rails ------------------------------------------------
|
12
|
+
|
13
|
+
RAILS_ENV="test"
|
14
|
+
RAILS_ROOT="#{DIRNAME}"
|
15
|
+
|
16
|
+
if !defined?(RAILS_DEFAULT_LOGGER)
|
17
|
+
FileUtils.mkdir_p File.dirname(LOGFILE)
|
18
|
+
RAILS_DEFAULT_LOGGER = Logger.new(LOGFILE)
|
19
|
+
RAILS_DEFAULT_LOGGER.level = Logger::DEBUG
|
20
|
+
end
|
data/test/test.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
DIRNAME = File.expand_path File.dirname(__FILE__)
|
3
|
+
Dir.chdir(DIRNAME)
|
4
|
+
|
5
|
+
#
|
6
|
+
# initialize the gem and the test runner
|
7
|
+
require '../init'
|
8
|
+
|
9
|
+
require 'logger'
|
10
|
+
require 'ruby-debug'
|
11
|
+
|
12
|
+
require "#{DIRNAME}/initializers/fake_rails.rb"
|
13
|
+
|
14
|
+
I18n.load_path += Dir["#{DIRNAME}/i18n/*.yml"]
|
15
|
+
|
16
|
+
# ---------------------------------------------------------------------
|
17
|
+
|
18
|
+
begin
|
19
|
+
require 'minitest-rg'
|
20
|
+
rescue MissingSourceFile
|
21
|
+
STDERR.puts "'gem install minitest-rg' gives you redgreen minitests"
|
22
|
+
require 'minitest/unit'
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# run tests
|
27
|
+
|
28
|
+
require "etest"
|
29
|
+
|
30
|
+
Etest.autorun
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: localite
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
version: "0.1"
|
9
|
+
platform: ruby
|
10
|
+
authors:
|
11
|
+
- pboy
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
|
16
|
+
date: 2010-05-11 00:00:00 +02:00
|
17
|
+
default_executable:
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: i18n
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
segments:
|
27
|
+
- 0
|
28
|
+
version: "0"
|
29
|
+
type: :runtime
|
30
|
+
version_requirements: *id001
|
31
|
+
description: An easy to use localization gem.
|
32
|
+
email: eno-pboy@open-lab.org
|
33
|
+
executables: []
|
34
|
+
|
35
|
+
extensions: []
|
36
|
+
|
37
|
+
extra_rdoc_files:
|
38
|
+
- lib/localite.rb
|
39
|
+
- lib/localite/rails_filter.rb
|
40
|
+
- lib/localite/scope.rb
|
41
|
+
- lib/localite/settings.rb
|
42
|
+
- lib/localite/template.rb
|
43
|
+
- lib/localite/translate.rb
|
44
|
+
- tasks/echoe.rake
|
45
|
+
files:
|
46
|
+
- Manifest
|
47
|
+
- Rakefile
|
48
|
+
- VERSION
|
49
|
+
- config/dependencies.rb
|
50
|
+
- config/gem.yml
|
51
|
+
- init.rb
|
52
|
+
- lib/localite.rb
|
53
|
+
- lib/localite/rails_filter.rb
|
54
|
+
- lib/localite/scope.rb
|
55
|
+
- lib/localite/settings.rb
|
56
|
+
- lib/localite/template.rb
|
57
|
+
- lib/localite/translate.rb
|
58
|
+
- localite.tmproj
|
59
|
+
- script/console
|
60
|
+
- script/rebuild
|
61
|
+
- tasks/echoe.rake
|
62
|
+
- test/i18n/de.yml
|
63
|
+
- test/initializers/fake_rails.rb
|
64
|
+
- test/test.rb
|
65
|
+
- localite.gemspec
|
66
|
+
has_rdoc: true
|
67
|
+
homepage: http://github.com/pboy/localite
|
68
|
+
licenses: []
|
69
|
+
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options:
|
72
|
+
- --line-numbers
|
73
|
+
- --inline-source
|
74
|
+
- --title
|
75
|
+
- Localite
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
segments:
|
90
|
+
- 1
|
91
|
+
- 2
|
92
|
+
version: "1.2"
|
93
|
+
requirements: []
|
94
|
+
|
95
|
+
rubyforge_project: localite
|
96
|
+
rubygems_version: 1.3.6
|
97
|
+
signing_key:
|
98
|
+
specification_version: 3
|
99
|
+
summary: An easy to use localization gem.
|
100
|
+
test_files: []
|
101
|
+
|