localite 0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|