l10nizer 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,50 @@
1
+ L10nizer
2
+ ========
3
+
4
+ Automagic _ex post facto_ localisation for Rails templates.
5
+
6
+ What it does
7
+ ------------
8
+
9
+ Processes all your `html.erb` templates, extracts text, replaces it with `t()` calls, and generates a YAML file of localisations.
10
+
11
+ For example, given a file `app/views/things/show.html.erb` with this content:
12
+
13
+ <div class="thing">
14
+ <h1>Some heading</h1>
15
+ <p>This thing is called <%= h(@thing.name)</p>
16
+ </div>
17
+
18
+ l10nizer will change it to:
19
+
20
+ <div class="thing">
21
+ <h1><%= t("things.some_heading") %></h1>
22
+ <p><%= t("things.this_thing_is_called_a", :a => (h(@thing.name))) %></p>
23
+ </div>
24
+
25
+ and generate the following entries in `config/locales/l10nized.yml`:
26
+
27
+ things:
28
+ some_heading: Some heading
29
+ this_thing_is_called_a: This thing is called {{a}}
30
+
31
+ You can then use `l10nized.yml` as a basis for the localisation file for your current locale, e.g. `en_GB.yml`.
32
+
33
+ Usage
34
+ -----
35
+
36
+ From within a Rails application directory:
37
+
38
+ l10nizer
39
+
40
+ Specifying the application path explicitly:
41
+
42
+ l10nizer /path/to/my/rails/app
43
+
44
+ Limitations
45
+ -----------
46
+
47
+ * Perhaps ironically for a _localisation_ utility, l10nizer assumes that your templates are written in English or generally in ASCII, and ignores non-alphanumeric content when generating localisation keys. This could be fixed by modifying or replacing the L10nizer::KeyGenerator class.
48
+ * L10nizer takes no position on HTML entities or escaping. You __will__ need to review the changes it makes.
49
+ * Similarly, pluralisation is outside the scope of this application and will require attention.
50
+ * Strings that should be single entities but which contain HTML will be broken into multiple localisation strings.
data/Rakefile ADDED
@@ -0,0 +1,54 @@
1
+ require "rubygems"
2
+ require "rake/gempackagetask"
3
+ require "rake/testtask"
4
+ require "lib/l10nizer/version"
5
+
6
+ task :default => [:test]
7
+
8
+ Rake::TestTask.new("test") do |t|
9
+ t.libs << "test"
10
+ t.pattern = "test/**/test_*.rb"
11
+ t.verbose = true
12
+ end
13
+
14
+ task :default => :test
15
+
16
+ require "rake/testtask"
17
+ Rake::TestTask.new do |t|
18
+ t.libs << "test"
19
+ t.test_files = FileList["test/**/*_test.rb"]
20
+ t.verbose = true
21
+ end
22
+
23
+ spec = Gem::Specification.new do |s|
24
+ s.name = "l10nizer"
25
+ s.version = L10nizer::VERSION::STRING
26
+ s.summary = "Automatically extract strings from ERB templates and replace with calls to t()"
27
+ s.author = "Paul Battley"
28
+ s.email = "pbattley@gmail.com"
29
+
30
+ s.has_rdoc = false
31
+
32
+ s.files = %w(Rakefile README.md) + Dir.glob("{bin,test,lib}/**/*")
33
+ s.executables = FileList["bin/**"].map { |f| File.basename(f) }
34
+
35
+ s.require_paths = ["lib"]
36
+
37
+ s.add_dependency("treetop", ">= 1.2.6")
38
+ s.add_dependency("polyglot", ">= 0.2.5")
39
+
40
+ s.add_development_dependency("thoughtbot-shoulda")
41
+ end
42
+
43
+ Rake::GemPackageTask.new(spec) do |pkg|
44
+ pkg.gem_spec = spec
45
+
46
+ # Generate the gemspec file for github.
47
+ file = File.dirname(__FILE__) + "/#{spec.name}.gemspec"
48
+ File.open(file, "w") {|f| f << spec.to_ruby }
49
+ end
50
+
51
+ desc 'Clear out generated packages'
52
+ task :clean => [:clobber_package] do
53
+ rm "#{spec.name}.gemspec"
54
+ end
data/bin/l10nizer ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+ require "l10nizer"
3
+ require "yaml"
4
+ require "fileutils"
5
+
6
+ Dir.chdir(ARGV.first) if ARGV.first
7
+ templates = Dir["app/views/**/*.html.erb"]
8
+ raise "Can't find any templates in app/views." unless templates.any?
9
+
10
+ keygen = L10nizer::KeyGenerator.new
11
+ l10ns = {}
12
+
13
+ templates.each do |path|
14
+ keygen.namespace = path.split("/")[2]
15
+ source = File.read(path)
16
+ l10nizer = L10nizer::Processor.new(source, keygen)
17
+ l10ns.merge!(l10nizer.l10ns)
18
+ File.open(path, "w") do |f|
19
+ f << l10nizer.reformed
20
+ end
21
+ end
22
+
23
+ l10ns = l10ns.inject({}){ |hash, (key, value)|
24
+ parts = key.split(".")
25
+ parts[0 .. -2].inject(hash){ |h, k| h[k] ||= {} }[parts.last] = value
26
+ hash
27
+ }
28
+
29
+ FileUtils.mkdir_p("config/locales")
30
+ File.open("config/locales/l10nized.yml", "w") do |f|
31
+ f << l10ns.to_yaml
32
+ end
@@ -0,0 +1,53 @@
1
+ grammar HtmlErb
2
+ rule document
3
+ (html_comment / javascript / style / erb_control / whitespace / text / tag)* <Document>
4
+ end
5
+
6
+ rule html_comment
7
+ "<!--" ([^\-] / "-" [^\-] / "--" [^>])* "-->"
8
+ end
9
+
10
+ rule javascript
11
+ "<script" ([^<] / "<" [^/] / "</" [^s] / "</s" [^c] / "</sc" [^r] / "</scr" [^i] / "</scri" [^p] / "</scrip" [^t] / "</script" [^>"])* "</script>"
12
+ end
13
+
14
+ rule style
15
+ "<style" ([^<] / "<" [^/] / "</" [^s] / "</s" [^t] / "</st" [^y] / "</sty" [^l] / "</styl" [^e] / "</style" [^>"])* "</style>"
16
+ end
17
+
18
+ rule erb_control
19
+ "<%" [^=] ruby_code "%>"
20
+ end
21
+
22
+ rule tag
23
+ "<" (erb_control / erb_eval / [^>])+ ">"
24
+ end
25
+
26
+ rule whitespace
27
+ [\s]+
28
+ end
29
+
30
+ rule optional_whitespace
31
+ [\s]*
32
+ end
33
+
34
+ rule text
35
+ (optional_whitespace (erb_eval / inline_markup / word))+ <Text>
36
+ end
37
+
38
+ rule inline_markup
39
+ "<" "/"? ("em" / "strong") [^>]* ">"
40
+ end
41
+
42
+ rule word
43
+ [^<\s]+ <Word>
44
+ end
45
+
46
+ rule erb_eval
47
+ "<%=" ruby_code "%>" <Eval>
48
+ end
49
+
50
+ rule ruby_code
51
+ (("%" [^>]) / [^%])+
52
+ end
53
+ end
@@ -0,0 +1,41 @@
1
+ module L10nizer
2
+ class KeyGenerator
3
+ attr_accessor :namespace
4
+
5
+ def initialize
6
+ @seen = {}
7
+ end
8
+
9
+ def call(string)
10
+ provisional = [make_safe(namespace), make_safe(string)].compact * "."
11
+
12
+ until try(provisional, string)
13
+ provisional.sub!(/(?:_\d+)?$/){ |m| "_" + m.to_i.succ.to_s }
14
+ end
15
+
16
+ return provisional
17
+ end
18
+
19
+ def try(key, string)
20
+ if [nil, string].include?(@seen[key])
21
+ @seen[key] = string
22
+ true
23
+ else
24
+ false
25
+ end
26
+ end
27
+
28
+ def make_safe(string)
29
+ return nil if string.nil?
30
+ safe = string.
31
+ downcase.
32
+ gsub(/&[a-z0-9]{1,20};/, ""). # entities
33
+ gsub(/<[^>]*>/, ""). # html
34
+ gsub(/[^a-z0-9]+/, "_"). # non alphanumeric
35
+ slice(0, 40).
36
+ gsub(/^_|_$/, "") # leading/trailing _
37
+ safe = "unknown" if safe.empty?
38
+ safe
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,108 @@
1
+ module L10nizer
2
+ class NodeWrapperFactory
3
+ def self.wrap(node, keygen=nil)
4
+ case node
5
+ when HtmlErb::Text
6
+ TextNode.new(node, keygen)
7
+ when HtmlErb::Eval
8
+ EvalNode.new(node, keygen)
9
+ when HtmlErb::Word
10
+ WordNode.new(node)
11
+ else
12
+ BasicNode.new(node)
13
+ end
14
+ end
15
+ end
16
+
17
+ class BasicNode
18
+ def initialize(node, keygen=nil)
19
+ @node = node
20
+ @keygen = keygen
21
+ end
22
+
23
+ def l10n
24
+ {}
25
+ end
26
+
27
+ def to_s
28
+ @node.text_value
29
+ end
30
+
31
+ def evaluated?
32
+ false
33
+ end
34
+
35
+ def string?
36
+ false
37
+ end
38
+ end
39
+
40
+ class TextNode < BasicNode
41
+ def l10n
42
+ _, text = vars_and_text
43
+ text ? {key => text} : {}
44
+ end
45
+
46
+ def to_s
47
+ vars, _ = vars_and_text
48
+ return super unless vars
49
+
50
+ params = ['"' + key + '"']
51
+ vars.each_with_index do |v, i|
52
+ params << %{:#{variable_name(i)} => (#{v})}
53
+ end
54
+
55
+ %{<%= t(#{params * ", "}) %>}
56
+ end
57
+
58
+ private
59
+ def children
60
+ @node.children.map{ |e| NodeWrapperFactory.wrap(e) }
61
+ end
62
+
63
+ def variable_name(index)
64
+ ("a" .. "z").to_a[index]
65
+ end
66
+
67
+ def vars_and_text
68
+ @vars_and_text ||= (
69
+ if children.all?{ |c| c.evaluated? } || !children.any?{ |c| c.string? }
70
+ []
71
+ else
72
+ l10n = ""
73
+ vars = []
74
+ children.each do |e|
75
+ if e.evaluated?
76
+ l10n << "{{#{variable_name(vars.length)}}}"
77
+ vars << e.to_s
78
+ else
79
+ l10n << e.to_s
80
+ end
81
+ end
82
+ [vars, l10n]
83
+ end
84
+ )
85
+ end
86
+
87
+ def key
88
+ _, text = vars_and_text
89
+ @key ||= @keygen.call(text)
90
+ end
91
+ end
92
+
93
+ class EvalNode < BasicNode
94
+ def to_s
95
+ super[/\A<%=\s*(.*?)\s*%>\Z/, 1]
96
+ end
97
+
98
+ def evaluated?
99
+ true
100
+ end
101
+ end
102
+
103
+ class WordNode < BasicNode
104
+ def string?
105
+ true
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,20 @@
1
+ require "treetop"
2
+ require "polyglot"
3
+ require "l10nizer/grammar"
4
+
5
+ module HtmlErb
6
+ class Document < Treetop::Runtime::SyntaxNode
7
+ end
8
+
9
+ class Text < Treetop::Runtime::SyntaxNode
10
+ def children
11
+ elements.map{ |e| e.elements }.flatten
12
+ end
13
+ end
14
+
15
+ class Eval < Treetop::Runtime::SyntaxNode
16
+ end
17
+
18
+ class Word < Treetop::Runtime::SyntaxNode
19
+ end
20
+ end
@@ -0,0 +1,29 @@
1
+ require "l10nizer/parser"
2
+ require "l10nizer/node"
3
+
4
+ module L10nizer
5
+ class Processor
6
+ def initialize(html, keygen)
7
+ @html = html
8
+ @keygen = keygen
9
+ end
10
+
11
+ def l10ns
12
+ processed.inject({}){ |hash, node| hash.merge(node.l10n) }
13
+ end
14
+
15
+ def reformed
16
+ processed.map{ |e| e.to_s }.join
17
+ end
18
+
19
+ def processed
20
+ unless @processed
21
+ kcode = $KCODE
22
+ $KCODE = "n"
23
+ @processed = HtmlErbParser.new.parse(@html).elements.map{ |e| NodeWrapperFactory.wrap(e, @keygen) }
24
+ $KCODE = kcode
25
+ end
26
+ @processed
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ module L10nizer #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 9
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
data/lib/l10nizer.rb ADDED
@@ -0,0 +1,2 @@
1
+ require "l10nizer/processor"
2
+ require "l10nizer/keygen"
@@ -0,0 +1,34 @@
1
+ <li id="action_<%=h thing.whatsit.id %>" class="item underway">
2
+ <div class="wrap">
3
+ <div class="placeholder">
4
+ <%- if thing.whatsit.identity? -%>
5
+ <%- if thing.whatsit.identity.processed? -%>
6
+ <%= image_tag thing.whatsit.identity.url(:medium) %>
7
+ <%- else -%>
8
+ <%= t("general.processing_image") %>
9
+ <%- end -%>
10
+ <%- end -%>
11
+ </div>
12
+ <h3>
13
+ <% link_to(thing) do %>
14
+ <span><%=h thing.whatsit.name %></span><%=h thing.short_address %>
15
+ <% end %>
16
+ </h3>
17
+ </div>
18
+ <div class="details">
19
+ <div class="format">
20
+ <h4 class="obfuscate">Skills</h4>
21
+ <ul class="skills">
22
+ <% thing.whatsit.skills.each do |skill| %>
23
+ <li class="skill">
24
+ <%= skill_icon(skill, :small) %>
25
+ </li>
26
+ <% end %>
27
+ <li class="engagement">
28
+ <%= engagement_icon(4, :small) %>
29
+ </li>
30
+ </ul>
31
+ <%=h truncate(thing.whatsit.short_description, :length => 130) %>
32
+ </div>
33
+ </div>
34
+ </li>
@@ -0,0 +1,34 @@
1
+ <li id="action_<%=h thing.whatsit.id %>" class="item underway">
2
+ <div class="wrap">
3
+ <div class="placeholder">
4
+ <%- if thing.whatsit.identity? -%>
5
+ <%- if thing.whatsit.identity.processed? -%>
6
+ <%= image_tag thing.whatsit.identity.url(:medium) %>
7
+ <%- else -%>
8
+ <%= t("general.processing_image") %>
9
+ <%- end -%>
10
+ <%- end -%>
11
+ </div>
12
+ <h3>
13
+ <% link_to(thing) do %>
14
+ <span><%=h thing.whatsit.name %></span><%=h thing.short_address %>
15
+ <% end %>
16
+ </h3>
17
+ </div>
18
+ <div class="details">
19
+ <div class="format">
20
+ <h4 class="obfuscate"><%= t("skills") %></h4>
21
+ <ul class="skills">
22
+ <% thing.whatsit.skills.each do |skill| %>
23
+ <li class="skill">
24
+ <%= skill_icon(skill, :small) %>
25
+ </li>
26
+ <% end %>
27
+ <li class="engagement">
28
+ <%= engagement_icon(4, :small) %>
29
+ </li>
30
+ </ul>
31
+ <%=h truncate(thing.whatsit.short_description, :length => 130) %>
32
+ </div>
33
+ </div>
34
+ </li>
@@ -0,0 +1,68 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+
3
+ require "test/unit"
4
+ require "l10nizer/keygen"
5
+ require "shoulda"
6
+
7
+ class KeyGeneratorTest < Test::Unit::TestCase
8
+
9
+ def setup
10
+ @keygen = L10nizer::KeyGenerator.new
11
+ end
12
+
13
+ context "without namespacing" do
14
+ should "generate keys based on string" do
15
+ assert_equal "foo_bar_baz_a", @keygen.call("Foo bar baz {{a}}")
16
+ end
17
+
18
+ should "truncate exceptionally long keys" do
19
+ long = "blah_" * 20
20
+ short = "blah_blah_blah_blah_blah_blah_blah_blah"
21
+ assert_equal short, @keygen.call(long)
22
+ end
23
+
24
+ should "reuse key for same text" do
25
+ assert_equal @keygen.call("the same"), @keygen.call("the same")
26
+ end
27
+
28
+ should "prevent duplicate keys for different texts" do
29
+ assert_equal "a_thing", @keygen.call("a thing")
30
+ assert_equal "a_thing_1", @keygen.call("A thing")
31
+ assert_equal "a_thing_2", @keygen.call("A Thing")
32
+ end
33
+
34
+ should "generate non empty keys for punctuation" do
35
+ assert_not_equal "", @keygen.call("<>!@#%#.,")
36
+ end
37
+
38
+ should "skip entities in keys" do
39
+ assert_equal "foo_bar", @keygen.call("foo &apos; bar")
40
+ end
41
+
42
+ should "skip inline markup in keys" do
43
+ assert_equal "foo_bar", @keygen.call("foo <strong>bar</strong>")
44
+ end
45
+ end
46
+
47
+ context "with namespacing" do
48
+ setup do
49
+ @keygen.namespace = "ns1"
50
+ end
51
+
52
+ should "prepend namespace" do
53
+ assert_equal "ns1.foo", @keygen.call("Foo")
54
+ end
55
+
56
+ should "prevent duplicate keys for different texts" do
57
+ assert_equal "ns1.a_thing", @keygen.call("a thing")
58
+ assert_equal "ns1.a_thing_1", @keygen.call("A thing")
59
+ assert_equal "ns1.a_thing_2", @keygen.call("A Thing")
60
+ end
61
+
62
+ should "check duplication by namespace" do
63
+ assert_equal "ns1.a_thing", @keygen.call("a thing")
64
+ @keygen.namespace = "ns2"
65
+ assert_equal "ns2.a_thing", @keygen.call("A thing")
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,162 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+
3
+ require "test/unit"
4
+ require "l10nizer/processor"
5
+ require "shoulda"
6
+
7
+ class ProcessorTest < Test::Unit::TestCase
8
+
9
+ class DumbKeyGenerator
10
+ def call(string)
11
+ string.downcase.gsub(/[^a-z0-9]+/, "_").gsub(/^_|_$/, "")[0, 40]
12
+ end
13
+ end
14
+
15
+ context "when finding text" do
16
+ setup do
17
+ html = "just some text"
18
+ @l10nizer = L10nizer::Processor.new(html, DumbKeyGenerator.new)
19
+ end
20
+
21
+ should "pass key to t()" do
22
+ expected = %{<%= t("just_some_text") %>}
23
+ assert_equal expected, @l10nizer.reformed
24
+ end
25
+
26
+ should "extract l10n strings" do
27
+ expected = {"just_some_text" => "just some text"}
28
+ assert_equal expected, @l10nizer.l10ns
29
+ end
30
+ end
31
+
32
+ context "when interpolating inline eval" do
33
+ setup do
34
+ html = "String <%= 27 %> with <%= 42 %>"
35
+ @l10nizer = L10nizer::Processor.new(html, DumbKeyGenerator.new)
36
+ end
37
+
38
+ should "pass values to t()" do
39
+ expected = %{<%= t("string_a_with_b", :a => (27), :b => (42)) %>}
40
+ assert_equal expected, @l10nizer.reformed
41
+ end
42
+
43
+ should "extract l10n strings" do
44
+ expected = {"string_a_with_b" => "String {{a}} with {{b}}"}
45
+ assert_equal expected, @l10nizer.l10ns
46
+ end
47
+ end
48
+
49
+ context "when interpolating in multiple text strings" do
50
+ setup do
51
+ html = "<p>String <%= 27 %> with <%= 42 %></p><p>Another <%= 'x' %></p>"
52
+ @l10nizer = L10nizer::Processor.new(html, DumbKeyGenerator.new)
53
+ end
54
+
55
+ should "pass values to t() reusing placeholder variables" do
56
+ expected = %{<p><%= t("string_a_with_b", :a => (27), :b => (42)) %></p><p><%= t("another_a", :a => ('x')) %></p>}
57
+ assert_equal expected, @l10nizer.reformed
58
+ end
59
+
60
+ should "extract l10n strings with placeholder variables" do
61
+ expected = {"string_a_with_b" => "String {{a}} with {{b}}", "another_a" => "Another {{a}}"}
62
+ assert_equal expected, @l10nizer.l10ns
63
+ end
64
+ end
65
+
66
+ should "not try to localise inline eval on its own" do
67
+ html = "<p><%= 27 %></p>"
68
+ l10nizer = L10nizer::Processor.new(html, DumbKeyGenerator.new)
69
+ assert_equal html, l10nizer.reformed
70
+ end
71
+
72
+ should "not try to localise an HTML comment" do
73
+ html = "<!-- <p><%= 27 %></p> --> <p> <!-- fooo --> </p>"
74
+ l10nizer = L10nizer::Processor.new(html, DumbKeyGenerator.new)
75
+ assert_equal html, l10nizer.reformed
76
+ end
77
+
78
+ should "not try to localise Javascript" do
79
+ html = "<script>var a = 3;</script> <script>var b = 'b';</script>"
80
+ l10nizer = L10nizer::Processor.new(html, DumbKeyGenerator.new)
81
+ assert_equal html, l10nizer.reformed
82
+ end
83
+
84
+ should "not try to localise inline styles" do
85
+ html = %{<style type="text/css">\nhtml.js .nojs {display: none; background:#fff!important;}\n</style>}
86
+ l10nizer = L10nizer::Processor.new(html, DumbKeyGenerator.new)
87
+ assert_equal html, l10nizer.reformed
88
+ end
89
+
90
+ should "not try to localise control inside a tag" do
91
+ html = %{<div class="user-skills block <% unless @user.skills.any? %>blank<% end %>">}
92
+ l10nizer = L10nizer::Processor.new(html, DumbKeyGenerator.new)
93
+ assert_equal html, l10nizer.reformed
94
+ end
95
+
96
+ context "when string contains inline markup" do
97
+ setup do
98
+ html = "<p>String with <strong>strong</strong> and <em>emphasised</em> text</p>"
99
+ @l10nizer = L10nizer::Processor.new(html, lambda{ "key" })
100
+ end
101
+
102
+ should "include that markup in text" do
103
+ expected = "String with <strong>strong</strong> and <em>emphasised</em> text"
104
+ assert_equal [expected], @l10nizer.l10ns.values
105
+ end
106
+
107
+ should "use only one localisation" do
108
+ expected = %{<p><%= t("key") %></p>}
109
+ assert_equal expected, @l10nizer.reformed
110
+ end
111
+ end
112
+
113
+ should "not consider <span> to be inline markup" do
114
+ html = %{foo <span>bar</span>}
115
+ l10nizer = L10nizer::Processor.new(html, DumbKeyGenerator.new)
116
+ assert_equal ["bar", "foo"], l10nizer.l10ns.values.sort
117
+ end
118
+
119
+ context "when parsing a sample document" do
120
+ setup do
121
+ @html = File.read(File.join(File.dirname(__FILE__), "samples", "input.html.erb"))
122
+ @expected = File.read(File.join(File.dirname(__FILE__), "samples", "output.html.erb"))
123
+ @l10nizer = L10nizer::Processor.new(@html, DumbKeyGenerator.new)
124
+ end
125
+
126
+ should "replace embedded text" do
127
+ actual = @l10nizer.reformed
128
+ #@expected.split(/\n/).zip(actual.split(/\n/)).each do |a, b|
129
+ # puts a, b unless a == b
130
+ #end
131
+ assert_equal @expected, actual
132
+ end
133
+
134
+ should "extract l10n strings" do
135
+ expected = {"skills" => "Skills"}
136
+ assert_equal expected, @l10nizer.l10ns
137
+ end
138
+ end
139
+
140
+ context "when $KCODE is 'UTF8'" do
141
+ setup do
142
+ @kcode = $KCODE
143
+ $KCODE = "UTF8"
144
+ end
145
+
146
+ teardown do
147
+ $KCODE = @kcode
148
+ end
149
+
150
+ should "parse multi-byte characters in strings" do
151
+ html = "<p>We’ve</p>"
152
+ l10nizer = L10nizer::Processor.new(html, DumbKeyGenerator.new)
153
+ assert_equal ["We’ve"], l10nizer.l10ns.values
154
+ end
155
+
156
+ should "not change $KCODE" do
157
+ l10nizer = L10nizer::Processor.new("", DumbKeyGenerator.new)
158
+ ignore = l10nizer.l10ns.values
159
+ assert_equal "UTF8", $KCODE
160
+ end
161
+ end
162
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: l10nizer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.9
5
+ platform: ruby
6
+ authors:
7
+ - Paul Battley
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-11 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: treetop
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.6
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: polyglot
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.2.5
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: thoughtbot-shoulda
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ description:
46
+ email: pbattley@gmail.com
47
+ executables:
48
+ - l10nizer
49
+ extensions: []
50
+
51
+ extra_rdoc_files: []
52
+
53
+ files:
54
+ - Rakefile
55
+ - README.md
56
+ - bin/l10nizer
57
+ - test/samples/output.html.erb
58
+ - test/samples/input.html.erb
59
+ - test/test_key_generator.rb
60
+ - test/test_processor.rb
61
+ - lib/l10nizer/grammar.treetop
62
+ - lib/l10nizer/node.rb
63
+ - lib/l10nizer/parser.rb
64
+ - lib/l10nizer/processor.rb
65
+ - lib/l10nizer/keygen.rb
66
+ - lib/l10nizer/version.rb
67
+ - lib/l10nizer.rb
68
+ has_rdoc: true
69
+ homepage:
70
+ licenses: []
71
+
72
+ post_install_message:
73
+ rdoc_options: []
74
+
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: "0"
82
+ version:
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: "0"
88
+ version:
89
+ requirements: []
90
+
91
+ rubyforge_project:
92
+ rubygems_version: 1.3.5
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: Automatically extract strings from ERB templates and replace with calls to t()
96
+ test_files: []
97
+