i15r 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ *.rbc
2
+ pkg/
data/CHANGELOG ADDED
@@ -0,0 +1,5 @@
1
+ v0.1.2 More i18n in rails helpers, suppress printing of message strings in test mode, script can run on several files
2
+
3
+ v0.1.1 Whitespace issues cleared up.
4
+
5
+ v0.1 First version.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Balint Erdi (balint.erdi@gmail.com)
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/Manifest ADDED
@@ -0,0 +1,12 @@
1
+ bin/i15r
2
+ CHANGELOG
3
+ i15r.gemspec
4
+ init.rb
5
+ lib/i15r.rb
6
+ Manifest
7
+ MIT-LICENSE
8
+ Rakefile
9
+ README.markdown
10
+ spec/i15r_spec.rb
11
+ tasks/i15r.rake
12
+ todos.markdown
data/README.markdown ADDED
@@ -0,0 +1,55 @@
1
+ # I15r
2
+
3
+ ## Summary
4
+
5
+ I15r (Internationalizer) searches for all the non-i18n texts in erb views in the given files/directory and replaces them with I18n messages. The message string is based on the file in which the text was found and the text itself that was replaced.
6
+
7
+ E.g
8
+
9
+ (in file app/views/users/new.html.erb)
10
+ <label for="user-name">Name</label>
11
+ <input type="text" id="user-name" name="user[name]" />
12
+
13
+ will be replaced by:
14
+
15
+ (in file app/views/users/new.html.erb)
16
+ <label for="user-name"><%= I18n.t("users.new.name") %></label>
17
+ <input type="text" id="user-name" name="user[name]" />
18
+
19
+ and
20
+
21
+ (in file app/views/member/users/edit.html.erb)
22
+ <label for="user-name">Name</label>
23
+ <input type="text" id="user-name" name="user[name]" />
24
+
25
+ will be replaced by
26
+
27
+ (in file app/views/member/users/edit.html.erb)
28
+ <label for="user-name"><%= I18n.t("member.users.edit.name") %></label>
29
+ <input type="text" id="user-name" name="user[name]" />
30
+
31
+ ## Installation
32
+
33
+ gem install i15r --source http://gemcutter.org
34
+
35
+ ## Usage
36
+
37
+ ### Convert a single file
38
+
39
+ i15r path/leading/to/view
40
+
41
+ ### Convert all files in a directory (deep search)
42
+
43
+ i15r path/leading/to/directory
44
+
45
+ All files with an erb suffix will be converted.
46
+
47
+ ### Dry run
48
+
49
+ By default, i15r overwrites all the source files with the i18n message strings it generates. If you first want to see what would be replaced, you should do:
50
+
51
+ i15r app/views/users -p
52
+
53
+ ## Licensing, contribution
54
+
55
+ The source code of this gem can be found at [http://github.com/balinterdi/i15r/](http://github.com/balinterdi/i15r/). It is released under the MIT-LICENSE, so you can basically do anything with it. However, if you think your modifications only make the tool better, please send a pull request or patch and I will consider merging in your changes. Any suggestions or feedback are welcome to <balint@bucionrails.com>.
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ require 'rake'
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |gemspec|
6
+ gemspec.name = "i15r"
7
+ gemspec.summary = "The internationalizer. Makes your Ruby app international"
8
+ gemspec.description = <<-EOF
9
+ The internationalizer. Replaces plain text strings in your views and replaces them with I18n message strings so you only have to provide the translations.
10
+ EOF
11
+ gemspec.email = "balint.erdi@gmail.com"
12
+ gemspec.homepage = "http://github.com/balinterdi/i15r"
13
+ gemspec.authors = ["Balint Erdi"]
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
18
+ end
19
+
20
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.0
data/bin/i15r ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
4
+
5
+ require 'i15r'
6
+
7
+ @i15r = I15R::Base.new
8
+ @i15r.instance_eval do
9
+ parse_options(ARGV)
10
+ internationalize!(ARGV[-1])
11
+ end
data/i15r.gemspec ADDED
@@ -0,0 +1,71 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{i15r}
8
+ s.version = "0.3.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Balint Erdi"]
12
+ s.date = %q{2009-12-08}
13
+ s.default_executable = %q{i15r}
14
+ s.description = %q{ The internationalizer. Replaces plain text strings in your views and replaces them with I18n message strings so you only have to provide the translations.
15
+ }
16
+ s.email = %q{balint.erdi@gmail.com}
17
+ s.executables = ["i15r"]
18
+ s.extra_rdoc_files = [
19
+ "README.markdown"
20
+ ]
21
+ s.files = [
22
+ ".gitignore",
23
+ "CHANGELOG",
24
+ "MIT-LICENSE",
25
+ "Manifest",
26
+ "README.markdown",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "bin/i15r",
30
+ "i15r.gemspec",
31
+ "init.rb",
32
+ "lib/i15r.rb",
33
+ "lib/i15r/base.rb",
34
+ "lib/i15r/pattern_matcher.rb",
35
+ "lib/i15r/pattern_matchers/base.rb",
36
+ "lib/i15r/pattern_matchers/rails_helper_matcher.rb",
37
+ "lib/i15r/pattern_matchers/tag_attribute_matcher.rb",
38
+ "lib/i15r/pattern_matchers/tag_content_matcher.rb",
39
+ "spec/i15r_spec.rb",
40
+ "spec/pattern_matcher_spec.rb",
41
+ "spec/rails_helper_matcher_spec.rb",
42
+ "spec/spec.opts",
43
+ "spec/tag_attribute_matcher_spec.rb",
44
+ "spec/tag_content_matcher_spec.rb",
45
+ "tasks/i15r.rake",
46
+ "todos.markdown"
47
+ ]
48
+ s.homepage = %q{http://github.com/balinterdi/i15r}
49
+ s.rdoc_options = ["--charset=UTF-8"]
50
+ s.require_paths = ["lib"]
51
+ s.rubygems_version = %q{1.3.5}
52
+ s.summary = %q{The internationalizer. Makes your Ruby app international}
53
+ s.test_files = [
54
+ "spec/i15r_spec.rb",
55
+ "spec/pattern_matcher_spec.rb",
56
+ "spec/rails_helper_matcher_spec.rb",
57
+ "spec/tag_attribute_matcher_spec.rb",
58
+ "spec/tag_content_matcher_spec.rb"
59
+ ]
60
+
61
+ if s.respond_to? :specification_version then
62
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
63
+ s.specification_version = 3
64
+
65
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
66
+ else
67
+ end
68
+ else
69
+ end
70
+ end
71
+
data/init.rb ADDED
@@ -0,0 +1,4 @@
1
+ # this will make it possible to install missing_t
2
+ # as a plugin for a Rails project
3
+ # (from http://railscasts.com/episodes/135-making-a-gem)
4
+ require "i15r"
data/lib/i15r.rb ADDED
@@ -0,0 +1,4 @@
1
+ $:.unshift File.expand_path(File.dirname(__FILE__))
2
+
3
+ require 'i15r/base'
4
+ require 'i15r/pattern_matcher'
data/lib/i15r/base.rb ADDED
@@ -0,0 +1,143 @@
1
+ require "optparse"
2
+ require "ostruct"
3
+
4
+ class AppFolderNotFound < Exception; end
5
+
6
+ module I15R
7
+ class Base
8
+ attr_reader :options
9
+
10
+ def self.get_i18n_message_string(text, prefix)
11
+ key = text.strip.downcase.gsub(/\s/, '_').gsub(/[\W]/, '')
12
+ indent = ""
13
+ (0..prefix.split(".").size).each { |i| indent = " " + indent }
14
+ # silenced_if_testing do
15
+ # puts "#{indent}#{key}: #{text}"
16
+ # end
17
+ "#{prefix}.#{key}"
18
+ end
19
+
20
+ def initialize
21
+ @options = OpenStruct.new
22
+ @options.prefix = nil
23
+ @options
24
+ end
25
+
26
+ def parse_options(args)
27
+ opts = OptionParser.new do |opts|
28
+ opts.banner = "Usage: ruby i15r.rb [options] <path_to_internationalize>"
29
+ opts.on("--prefix PREFIX",
30
+ "apply PREFIX to generated I18n messages instead of deriving it from the path") do |prefix|
31
+ @options.prefix = prefix
32
+ end
33
+ end
34
+
35
+ if args.length.zero?
36
+ puts opts.banner
37
+ exit
38
+ end
39
+
40
+ opts.on_tail("-p", "--pretend", "Do not write the files, just show what would be replaced") do
41
+ @options.dry_run = true
42
+ end
43
+
44
+ opts.on_tail("-h", "--help", "Show this message") do
45
+ puts opts
46
+ exit
47
+ end
48
+
49
+ opts.on_tail("--version", "Show version") do
50
+ puts "0.0.1"
51
+ exit
52
+ end
53
+
54
+ opts.parse!(args)
55
+ # @options
56
+ end
57
+
58
+ def prefix
59
+ @options.prefix
60
+ end
61
+
62
+ def dry_run?
63
+ !!@options.dry_run
64
+ end
65
+
66
+ def file_path_to_message_prefix(file)
67
+ segments = File.expand_path(file).split('/').select { |segment| !segment.empty? }
68
+ subdir = %w(views helpers controllers models).find do |app_subdir|
69
+ segments.index(app_subdir)
70
+ end
71
+ if subdir.nil?
72
+ raise AppFolderNotFound, "No app. subfolders were found to determine prefix. Path is #{File.expand_path(file)}"
73
+ end
74
+ first_segment_index = segments.index(subdir) + 1
75
+ file_name_without_extensions = segments.last.split('.')[0..0]
76
+ path_segments = segments.slice(first_segment_index...-1)
77
+ (path_segments + file_name_without_extensions).join('.')
78
+ end
79
+
80
+ def get_content_from(file)
81
+ File.read(File.expand_path(file))
82
+ end
83
+
84
+ def write_content_to(file, content)
85
+ open(File.expand_path(file), "w") { |f| f.write(content) }
86
+ end
87
+
88
+ def show_diff(plain_row, i9l_row)
89
+ silenced_if_testing do
90
+ $stdout.puts "- #{plain_row}"
91
+ $stdout.puts "+ #{i9l_row}"
92
+ end
93
+ end
94
+
95
+ def internationalize_file(file)
96
+ text = get_content_from(file)
97
+ prefix = self.prefix || file_path_to_message_prefix(file)
98
+ i18ned_text = sub_plain_strings(text, prefix)
99
+ write_content_to(file, i18ned_text) unless dry_run?
100
+ end
101
+
102
+ def display_indented_header(prefix)
103
+ silenced_if_testing do
104
+ puts "en:"
105
+ end
106
+ prefix_parts = prefix.split(".").each_with_index do |p, i|
107
+ p = "#{p}:"
108
+ (0..i).each { |i| p = " " + p }
109
+ silenced_if_testing do
110
+ puts "#{p}"
111
+ end
112
+ end
113
+ end
114
+
115
+ def sub_plain_strings(text, prefix)
116
+ #TODO: find out how to display diff rows
117
+ I15R::PatternMatchers::Base.run(text, prefix) do |plain_row, i9l_row|
118
+ show_diff(plain_row, i9l_row)
119
+ end
120
+ end
121
+
122
+ def internationalize!(path)
123
+ files = path =~ /.erb$/ ? [path] : Dir.glob("#{path}/**/*.erb")
124
+ files.each { |file| internationalize_file(file) }
125
+ end
126
+
127
+ private
128
+ def silenced_if_testing
129
+ if testing?
130
+ orig_stdout = $stdout
131
+ $stdout = File.new('/dev/null', 'w')
132
+ end
133
+ yield
134
+ if testing?
135
+ $stdout = orig_stdout
136
+ end
137
+ end
138
+
139
+ def testing?
140
+ $testing
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,4 @@
1
+ require 'i15r/pattern_matchers/base'
2
+ require 'i15r/pattern_matchers/tag_attribute_matcher'
3
+ require 'i15r/pattern_matchers/rails_helper_matcher'
4
+ require 'i15r/pattern_matchers/tag_content_matcher'
@@ -0,0 +1,35 @@
1
+ module I15R
2
+ module PatternMatchers
3
+ class Base
4
+ # def self.inherited(descendant)
5
+ # descendant.methods(false).grep /^match/ do |matcher_method|
6
+ # descendant.method(matcher_method).call
7
+ # end
8
+ # end
9
+
10
+ def self.matches(&block)
11
+ @@matchers ||= []
12
+ @@matchers.push(block)
13
+ end
14
+
15
+ def self.run(text, prefix)
16
+ i18ned_text = text
17
+ @@matchers.each do |matcher|
18
+ m = matcher.call(text, prefix)
19
+ unless m.nil?
20
+ plain_row, i18ned_row = m
21
+ yield plain_row, i18ned_row if block_given?
22
+ i18ned_text.gsub!(plain_row, i18ned_row)
23
+ end
24
+ end
25
+ i18ned_text
26
+ end
27
+
28
+ #TODO: use method_added to add to matchers so that
29
+ # matchers do not have to be explicitly registered.
30
+ def self.register_matcher(matcher_method)
31
+ self.method(matcher_method).call
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,69 @@
1
+ require 'i15r/base'
2
+
3
+ module I15R
4
+ module PatternMatchers
5
+ class RailsHelperMatcher < Base
6
+
7
+ def self.match_link_to_title
8
+ patt = /^(.*)<%=\s*link_to\s+['"](.*?)['"]\s*,(.*)%>(.*)$/
9
+ matches do |text, prefix|
10
+ if m = patt.match(text)
11
+ i18n_string = I15R::Base.get_i18n_message_string(m[2], prefix)
12
+ i18ned_row = %(#{m[1]}<%= link_to I18n.t("#{i18n_string}"),#{m[3]}%>#{m[4]})
13
+ [m[0], i18ned_row]
14
+ end
15
+ end
16
+ end
17
+ register_matcher :match_link_to_title
18
+
19
+ def self.match_label_helper_text
20
+ patt = /^(.*)<%=(.*)\.label(.*),\s*['"](.*?)['"]\s*%>(.*)$/
21
+ matches do |text, prefix|
22
+ if m = patt.match(text)
23
+ i18n_string = I15R::Base.get_i18n_message_string(m[4], prefix)
24
+ i18ned_row = %(#{m[1]}<%=#{m[2]}.label#{m[3]}, I18n.t("#{i18n_string}") %>#{m[5]})
25
+ [m[0], i18ned_row]
26
+ end
27
+ end
28
+ end
29
+ register_matcher :match_label_helper_text
30
+
31
+ def self.match_label_tag_helper_text
32
+ patt = /^(.*)<%=(.*)label_tag (.*),\s*['"](.*?)['"]\s*%>(.*)$/
33
+ matches do |text, prefix|
34
+ if m = patt.match(text)
35
+ i18n_string = I15R::Base.get_i18n_message_string(m[4], prefix)
36
+ i18ned_row = %(#{m[1]}<%=#{m[2]}label_tag #{m[3]}, I18n.t("#{i18n_string}") %>#{m[5]})
37
+ [m[0], i18ned_row]
38
+ end
39
+ end
40
+ end
41
+ register_matcher :match_label_tag_helper_text
42
+
43
+ def self.match_submit_helper_text
44
+ patt = /^(.*)<%=(.*)\.submit\s*['"](.*?)['"]\s*%>(.*)$/
45
+ matches do |text, prefix|
46
+ if m = patt.match(text)
47
+ i18n_string = I15R::Base.get_i18n_message_string(m[3], prefix)
48
+ i18ned_row = %(#{m[1]}<%=#{m[2]}.submit I18n.t("#{i18n_string}") %>#{m[4]})
49
+ [m[0], i18ned_row]
50
+ end
51
+ end
52
+ end
53
+ register_matcher :match_submit_helper_text
54
+
55
+ def self.match_submit_tag_helper_text
56
+ patt = /^(.*)<%=\s*submit_tag\s*['"](.*?)['"]\s*%>(.*)$/
57
+ matches do |text, prefix|
58
+ if m = patt.match(text)
59
+ i18n_string = I15R::Base.get_i18n_message_string(m[2], prefix)
60
+ i18ned_row = %(#{m[1]}<%= submit_tag I18n.t("#{i18n_string}") %>#{m[3]})
61
+ [m[0], i18ned_row]
62
+ end
63
+ end
64
+ end
65
+ register_matcher :match_submit_tag_helper_text
66
+
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,21 @@
1
+ require 'i15r/base'
2
+
3
+ module I15R
4
+ module PatternMatchers
5
+ class TagAttributeMatcher < Base
6
+
7
+ def self.match_title_attribute
8
+ patt = /^(.*)(<a\s+.*title=)['"](.*?)['"](.*)/
9
+ matches do |text, prefix|
10
+ if m = patt.match(text)
11
+ i18n_string = I15R::Base.get_i18n_message_string(m[3], prefix)
12
+ i18ned_row = %(#{m[1]}#{m[2]}"<%= I18n.t("#{i18n_string}") %>"#{m[4]})
13
+ [m[0], i18ned_row]
14
+ end
15
+ end
16
+ end
17
+ register_matcher :match_title_attribute
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ require 'i15r/base'
2
+
3
+ module I15R
4
+ module PatternMatchers
5
+ class TagContentMatcher < Base
6
+ def self.match_tag_content
7
+ patt = /^(.*)>(\s*)(\w[\s\w:'"!?\.,]+)\s*<\/(.*)$/
8
+ matches do |text, prefix|
9
+ if m = patt.match(text)
10
+ i18n_string = I15R::Base.get_i18n_message_string(m[3], prefix)
11
+ ending_punctuation = m[3][/([?.!:\s]*)$/, 1]
12
+ i18ned_row = %(#{m[1]}>#{m[2]}<%= I18n.t("#{i18n_string}") %>#{ending_punctuation.to_s}</#{m[4]})
13
+ [m[0], i18ned_row]
14
+ end
15
+ end
16
+ end
17
+ register_matcher :match_tag_content
18
+ end
19
+ end
20
+ end
data/spec/i15r_spec.rb ADDED
@@ -0,0 +1,130 @@
1
+ # puts %(#{File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib", "i15r")})
2
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
3
+
4
+ require "i15r"
5
+ require "fakefs"
6
+
7
+ $testing = true
8
+
9
+ describe I15R::Base do
10
+
11
+ before do
12
+ @i15r = I15R::Base.new
13
+ end
14
+
15
+ describe "converting file paths to message prefixes" do
16
+
17
+ it "should correctly work from app root for views" do
18
+ @i15r.file_path_to_message_prefix("app/views/users/new.html.erb").should == "users.new"
19
+ end
20
+
21
+ it "should correctly work from app root for helpers" do
22
+ @i15r.file_path_to_message_prefix("app/helpers/users_helper.rb").should == "users_helper"
23
+ end
24
+
25
+ it "should correctly work from app root for controllers" do
26
+ @i15r.file_path_to_message_prefix("app/controllers/users_controller.rb").should == "users_controller"
27
+ end
28
+
29
+ it "should correctly work from app root for models" do
30
+ @i15r.file_path_to_message_prefix("app/models/user.rb").should == "user"
31
+ end
32
+
33
+ it "should correctly work from app root for deep dir. structures" do
34
+ @i15r.file_path_to_message_prefix("app/views/member/session/users/new.html.erb").should == "member.session.users.new"
35
+ end
36
+
37
+ it "should raise if path does not contain any Rails app directories" do
38
+ path = "projects/doodle.rb"
39
+ lambda { @i15r.file_path_to_message_prefix(path) }.should raise_error(AppFolderNotFound)
40
+ end
41
+ end
42
+
43
+ describe "dry_run?" do
44
+ it "should return true when in dry run mode" do
45
+ @i15r.options.dry_run = true
46
+ @i15r.dry_run?.should == true
47
+ end
48
+ it "should return false when not in dry run mode" do
49
+ @i15r.options.dry_run = false
50
+ @i15r.dry_run?.should == false
51
+ end
52
+ end
53
+
54
+ describe "turning plain messages into i18n message strings" do
55
+
56
+ it "should downcase a single word" do
57
+ I15R::Base.get_i18n_message_string("Name", "users.new").should == "users.new.name"
58
+ end
59
+
60
+ it "should replace spaces with underscores" do
61
+ I15R::Base.get_i18n_message_string("New name", "users.index").should == "users.index.new_name"
62
+ end
63
+
64
+ end
65
+
66
+ describe "when substituting the plain contents with i18n message strings" do
67
+ before do
68
+ @i15r.options.prefix = nil
69
+ @file_path = "app/views/users/new.html.erb"
70
+ File.open(@file_path, "w") { |f| f.write("<label for=\"user-name\">Name</label>") }
71
+ end
72
+
73
+ describe "and in dry-run mode" do
74
+ before do
75
+ @i15r.stub!(:dry_run?).and_return(true)
76
+ end
77
+ it "should not touch any files" do
78
+ @i15r.should_not_receive(:write_content_to)
79
+ @i15r.internationalize_file(@file_path)
80
+ end
81
+ it "should display the diff" do
82
+ @i15r.should_receive(:show_diff)
83
+ @i15r.internationalize_file(@file_path)
84
+ end
85
+ end
86
+
87
+ describe "and not in dry-run mode" do
88
+ before do
89
+ @i15r.stub!(:dry_run?).and_return(false)
90
+ end
91
+ it "should write the files" do
92
+ @i15r.should_receive(:write_content_to)
93
+ @i15r.internationalize_file(@file_path)
94
+ end
95
+ end
96
+ end
97
+
98
+ describe "when no prefix option was given" do
99
+ it "should correctly internationalize messages using a prefix derived from the path" do
100
+ message_prefix = "users.new"
101
+ plain_snippet = <<-EOS
102
+ <label for="user-name">Name</label>
103
+ <input type="text" id="user-name" name="user[name]" />
104
+ EOS
105
+ i18ned_snippet = <<-EOS
106
+ <label for="user-name"><%= I18n.t("#{message_prefix}.name") %></label>
107
+ <input type="text" id="user-name" name="user[name]" />
108
+ EOS
109
+ @i15r.sub_plain_strings(plain_snippet, message_prefix).should == i18ned_snippet
110
+ end
111
+ end # "when no prefix option was given"
112
+
113
+ describe "when an explicit prefix option was given" do
114
+ it "should correctly internationalize messages using the prefix" do
115
+ prefix_option = "mysite"
116
+ plain_snippet = <<-EOS
117
+ <label for="user-name">Name</label>
118
+ <input type="text" id="user-name" name="user[name]" />
119
+ EOS
120
+ i18ned_snippet = <<-EOS
121
+ <label for="user-name"><%= I18n.t("#{prefix_option}.name") %></label>
122
+ <input type="text" id="user-name" name="user[name]" />
123
+ EOS
124
+
125
+ @i15r.sub_plain_strings(plain_snippet, prefix_option).should == i18ned_snippet
126
+ end
127
+
128
+ end # "when an explicit prefix option was given"
129
+
130
+ end
@@ -0,0 +1,8 @@
1
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
2
+
3
+ require 'i15r/pattern_matcher'
4
+ require "spec"
5
+
6
+ describe I15R::PatternMatchers::Base do
7
+
8
+ end
@@ -0,0 +1,45 @@
1
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
2
+
3
+ require 'i15r/pattern_matcher'
4
+ require "spec"
5
+
6
+ # FIXME: since matcher blocks are added and executed in the Base class,
7
+ # tests are not independent: they are coupled through the Base's run method
8
+ describe I15R::PatternMatchers::RailsHelperMatcher do
9
+ it "should replace a title in a link_to helper" do
10
+ plain = %(want a <p class="highlighted"><%= link_to 'New user', new_user_path %>?</p>)
11
+ i18ned = %(want a <p class="highlighted"><%= link_to I18n.t("users.index.new_user"), new_user_path %>?</p>)
12
+ I15R::PatternMatchers::RailsHelperMatcher.run(plain, "users.index").should == i18ned
13
+ end
14
+
15
+ it "should replace a title in a link_to helper with html attributes" do
16
+ plain = %(<p><%= link_to "Create a new user", new_user_path, { :class => "add" } -%></p>)
17
+ i18ned = %(<p><%= link_to I18n.t("users.index.create_a_new_user"), new_user_path, { :class => "add" } -%></p>)
18
+ I15R::PatternMatchers::RailsHelperMatcher.run(plain, "users.index").should == i18ned
19
+ end
20
+
21
+ it "should replace the label text in a label helper" do
22
+ plain = %(<%= f.label :name, "Name" %>)
23
+ i18ned = %(<%= f.label :name, I18n.t("users.new.name") %>)
24
+ I15R::PatternMatchers::RailsHelperMatcher.run(plain, "users.new").should == i18ned
25
+ end
26
+
27
+ it "should replace the label text of a label_tag helper" do
28
+ plain = %(<%= label_tag :name, "Name" %>)
29
+ i18ned = %(<%= label_tag :name, I18n.t("users.new.name") %>)
30
+ I15R::PatternMatchers::RailsHelperMatcher.run(plain, "users.new").should == i18ned
31
+ end
32
+
33
+ it "should replace the title of a submit helper in a form builder" do
34
+ plain = %(<%= f.submit "Create user" %>)
35
+ i18ned = %(<%= f.submit I18n.t("users.new.create_user") %>)
36
+ I15R::PatternMatchers::RailsHelperMatcher.run(plain, "users.new").should == i18ned
37
+ end
38
+
39
+ it "should replace the title of a submit_tag helper" do
40
+ plain = %(<%= submit_tag "Create user" %>)
41
+ i18ned = %(<%= submit_tag I18n.t("users.new.create_user") %>)
42
+ I15R::PatternMatchers::RailsHelperMatcher.run(plain, "users.new").should == i18ned
43
+ end
44
+
45
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format profile
3
+ --timeout 20
4
+ --diff
@@ -0,0 +1,15 @@
1
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
2
+
3
+ require 'i15r/pattern_matcher'
4
+ require "spec"
5
+
6
+ # FIXME: since matcher blocks are added and executed in the Base class, that's what should be called
7
+ # in the tests. That's not elegant and tests are not independent: they are coupled through the Base's run method
8
+ describe I15R::PatternMatchers::TagAttributeMatcher do
9
+ it "should replace a link's title" do
10
+ plain = %(Site root\nThis is it: <a title="site root" href="/"><img src="site_logo.png" /></a>)
11
+ i18ned = %(Site root\nThis is it: <a title="<%= I18n.t("users.new.site_root") %>" href="/"><img src="site_logo.png" /></a>)
12
+ I15R::PatternMatchers::TagAttributeMatcher.run(plain, "users.new").should == i18ned
13
+ end
14
+
15
+ end
@@ -0,0 +1,38 @@
1
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
2
+
3
+ require 'i15r/pattern_matcher'
4
+ require "spec"
5
+
6
+ describe I15R::PatternMatchers::TagContentMatcher do
7
+
8
+ it "should replace a single word" do
9
+ plain = %(<label for="user-name">Name</label>)
10
+ i18ned = %(<label for="user-name"><%= I18n.t("users.new.name") %></label>)
11
+ I15R::PatternMatchers::TagContentMatcher.run(plain, "users.new").should == i18ned
12
+ end
13
+
14
+ it "should replace several words" do
15
+ plain = %(<label for="user-name">Earlier names</label>)
16
+ i18ned = %(<label for="user-name"><%= I18n.t("users.new.earlier_names") %></label>)
17
+ I15R::PatternMatchers::TagContentMatcher.run(plain, "users.new").should == i18ned
18
+ end
19
+
20
+ it "should remove punctuation from plain strings" do
21
+ plain = %(<label for="user-name">Got friends? A friend's name</label>)
22
+ i18ned = %(<label for="user-name"><%= I18n.t("users.new.got_friends_a_friends_name") %></label>)
23
+ I15R::PatternMatchers::TagContentMatcher.run(plain, "users.new").should == i18ned
24
+ end
25
+
26
+ it "should not remove punctuation outside plain strings" do
27
+ plain = %(<label for="user-name">A friend's name:</label>)
28
+ i18ned = %(<label for="user-name"><%= I18n.t("users.new.a_friends_name") %>:</label>)
29
+ I15R::PatternMatchers::TagContentMatcher.run(plain, "users.new").should == i18ned
30
+ end
31
+
32
+ it "should preserve whitespace in the content part of the tag" do
33
+ plain = %(<label for="user-name"> Name </label>)
34
+ i18ned = %(<label for="user-name"> <%= I18n.t("users.new.name") %> </label>)
35
+ I15R::PatternMatchers::TagContentMatcher.run(plain, "users.new").should == i18ned
36
+ end
37
+
38
+ end
data/tasks/i15r.rake ADDED
@@ -0,0 +1,8 @@
1
+ require 'spec/rake/spectask'
2
+
3
+ desc "Run all specs"
4
+ Spec::Rake::SpecTask.new('spec') do |t|
5
+ t.spec_files = FileList['spec/**/*spec.rb']
6
+ t.spec_opts = ['--options', 'spec/spec.opts']
7
+ end
8
+
data/todos.markdown ADDED
@@ -0,0 +1,36 @@
1
+ ### 0.1
2
+
3
+ * DONE bug: In messages ending in punctuation (e.g No tags.) the punctuation is removed when replaced (e.g <%= I18n.t("users.show.no_tags") %>)
4
+
5
+ ### 0.1.1
6
+
7
+ * DONE bug: indenting whitespace is removed around replaced messages
8
+ This is easy to fix, the whitespace has to be readded just like the punctuation
9
+
10
+ <% tags = @photo.tag_list %>
11
+ Tags:
12
+ <% if !tags.blank? %>
13
+
14
+ becomes
15
+
16
+ <% tags = @photo.tag_list %><%= I18n.t("mysite.tags") %><% if !tags.blank? %>
17
+
18
+ ### 0.2
19
+
20
+ * DONE title of links have to be internationailzed, e.g: <a title="Go back" href="...">
21
+ * DONE <%= f.label :body, "Question" %>
22
+ * DONE <%= label_tag :body, "Question" %>
23
+ * DONE <%= f.submit "Submit question" %>
24
+ * DONE <%= submit_tag "Submit question" %>
25
+ * DONE think about which rails helpers could be given text that needs to be internationalized (currently only link_to is scanned)
26
+ * DONE suppress printing of yaml strings (change by Alberto) when running the specs
27
+ * DONE make it possible to run i15r on several files
28
+
29
+ ### 0.?
30
+
31
+ * dry-run option: only show the diffs but do not actually overwrite the files
32
+ * make prefix not replace the inferred message string prefix, but really act as a prefix. (e.g if anetcom is given as a prefix, and the inferred message string is 'users.new' it should not be 'anetcom.name', but 'anetcom.users.new.name')
33
+ * handle non-ascii characters properly (UTF-8 support) when replacing them. Mañana should become I18n.t("prefix.manana"), for instance. That is, regular expressions should be utf-8 aware.
34
+ * write the necessary i18n strings back into the yaml file
35
+ * make interactive mode possible. the user is asked about each message to be replaced. he can choose to replace it, skip it or even edit it. Ideally the message would be shown in its context.
36
+
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: i15r
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Balint Erdi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-08 00:00:00 +01:00
13
+ default_executable: i15r
14
+ dependencies: []
15
+
16
+ description: " The internationalizer. Replaces plain text strings in your views and replaces them with I18n message strings so you only have to provide the translations.\n"
17
+ email: balint.erdi@gmail.com
18
+ executables:
19
+ - i15r
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.markdown
24
+ files:
25
+ - .gitignore
26
+ - CHANGELOG
27
+ - MIT-LICENSE
28
+ - Manifest
29
+ - README.markdown
30
+ - Rakefile
31
+ - VERSION
32
+ - bin/i15r
33
+ - i15r.gemspec
34
+ - init.rb
35
+ - lib/i15r.rb
36
+ - lib/i15r/base.rb
37
+ - lib/i15r/pattern_matcher.rb
38
+ - lib/i15r/pattern_matchers/base.rb
39
+ - lib/i15r/pattern_matchers/rails_helper_matcher.rb
40
+ - lib/i15r/pattern_matchers/tag_attribute_matcher.rb
41
+ - lib/i15r/pattern_matchers/tag_content_matcher.rb
42
+ - spec/i15r_spec.rb
43
+ - spec/pattern_matcher_spec.rb
44
+ - spec/rails_helper_matcher_spec.rb
45
+ - spec/spec.opts
46
+ - spec/tag_attribute_matcher_spec.rb
47
+ - spec/tag_content_matcher_spec.rb
48
+ - tasks/i15r.rake
49
+ - todos.markdown
50
+ has_rdoc: true
51
+ homepage: http://github.com/balinterdi/i15r
52
+ licenses: []
53
+
54
+ post_install_message:
55
+ rdoc_options:
56
+ - --charset=UTF-8
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ version:
71
+ requirements: []
72
+
73
+ rubyforge_project:
74
+ rubygems_version: 1.3.5
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: The internationalizer. Makes your Ruby app international
78
+ test_files:
79
+ - spec/i15r_spec.rb
80
+ - spec/pattern_matcher_spec.rb
81
+ - spec/rails_helper_matcher_spec.rb
82
+ - spec/tag_attribute_matcher_spec.rb
83
+ - spec/tag_content_matcher_spec.rb