ready_for_i18n 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/bin/ready_for_i18n +70 -0
- data/lib/base_extractor.rb +28 -0
- data/lib/i18n_automator.rb +22 -0
- data/lib/label_extractor.rb +24 -0
- data/lib/locale_dictionary.rb +21 -0
- data/lib/ready_for_i18n.rb +4 -0
- data/lib/text_extractor.rb +37 -0
- data/ready_for_i18n.gemspec +74 -0
- data/test/fixtures/index.html.erb +89 -0
- data/test/helper.rb +10 -0
- data/test/output/en.yml +4 -0
- data/test/output/label.html.erb +89 -0
- data/test/output/text.html.erb +89 -0
- data/test/test_base_extractor.rb +20 -0
- data/test/test_label_extractor.rb +22 -0
- data/test/test_locale_dictionary.rb +16 -0
- data/test/test_text_extrator.rb +21 -0
- metadata +91 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 zigzag
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
= ready_for_i18n
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
13
|
+
* Send me a pull request. Bonus points for topic branches.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2009 zigzag. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "ready_for_i18n"
|
8
|
+
gem.summary = "ready_for_i18n is a tool helping for the very first step of transfering your local Rails project to an i18n one."
|
9
|
+
gem.description = <<END_OF_DESC
|
10
|
+
ready_for_i18n will help you extract visible hard-coded text from your ERB view files,
|
11
|
+
then choose a proper key and replace them with the I18n.translate method like t(:login)
|
12
|
+
END_OF_DESC
|
13
|
+
|
14
|
+
gem.email = "zigzag.chen@gmail.com"
|
15
|
+
gem.homepage = "http://github.com/zigzag/ready_for_i18n"
|
16
|
+
gem.authors = ["zigzag"]
|
17
|
+
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
18
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
19
|
+
end
|
20
|
+
Jeweler::GemcutterTasks.new
|
21
|
+
rescue LoadError
|
22
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'rake/testtask'
|
26
|
+
Rake::TestTask.new(:test) do |test|
|
27
|
+
test.libs << 'lib' << 'test'
|
28
|
+
test.pattern = 'test/**/test_*.rb'
|
29
|
+
test.verbose = true
|
30
|
+
end
|
31
|
+
|
32
|
+
begin
|
33
|
+
require 'rcov/rcovtask'
|
34
|
+
Rcov::RcovTask.new do |test|
|
35
|
+
test.libs << 'test'
|
36
|
+
test.pattern = 'test/**/test_*.rb'
|
37
|
+
test.verbose = true
|
38
|
+
end
|
39
|
+
rescue LoadError
|
40
|
+
task :rcov do
|
41
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
task :test => :check_dependencies
|
46
|
+
|
47
|
+
task :default => :test
|
48
|
+
|
49
|
+
require 'rake/rdoctask'
|
50
|
+
Rake::RDocTask.new do |rdoc|
|
51
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
52
|
+
|
53
|
+
rdoc.rdoc_dir = 'rdoc'
|
54
|
+
rdoc.title = "ready_for_i18n #{version}"
|
55
|
+
rdoc.rdoc_files.include('README*')
|
56
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
57
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.2
|
data/bin/ready_for_i18n
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
4
|
+
|
5
|
+
help = <<HELP
|
6
|
+
******************************************************************************
|
7
|
+
ready_for_i18n is a handy tool in the first step of transfering your local
|
8
|
+
Rails project to an i18n one.
|
9
|
+
|
10
|
+
It will automatically extract hard-coded text from your ERB view file,
|
11
|
+
then choose a proper key and replace them with the I18n.translate method.
|
12
|
+
|
13
|
+
Basic Command Line Usage:
|
14
|
+
ready_for_i18n <path to ERB source files> <target path>
|
15
|
+
|
16
|
+
# Your erb files in source path will be transformed(i18n_ready)
|
17
|
+
# and copy to target file path,together with a locale file 'en.yml'.
|
18
|
+
|
19
|
+
# using the following options:
|
20
|
+
|
21
|
+
HELP
|
22
|
+
|
23
|
+
require 'optparse'
|
24
|
+
require 'fileutils'
|
25
|
+
require 'ready_for_i18n'
|
26
|
+
|
27
|
+
options = {}
|
28
|
+
opts = OptionParser.new do |opts|
|
29
|
+
opts.banner = help
|
30
|
+
opts.on("--locale [LOCALE]", "Generating for the specified locale (default locale 'en')") do |locale|
|
31
|
+
options['locale'] = locale unless locale.nil?
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on("--ext [EXTENSION]", "The file extension name of your views(default '.html.erb')") do |extension|
|
35
|
+
options['extension'] = extension unless extension.nil?
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
# Read command line options into `options` hash
|
41
|
+
opts.parse!
|
42
|
+
|
43
|
+
# Get source and destintation from command line
|
44
|
+
case ARGV.size
|
45
|
+
when 2
|
46
|
+
options['source'] = ARGV[0]
|
47
|
+
options['destination'] = ARGV[1]
|
48
|
+
else
|
49
|
+
puts "Invalid options. Run `ready_for_i18n --help` for assistance."
|
50
|
+
exit(1)
|
51
|
+
end
|
52
|
+
|
53
|
+
def excute(src_path,target_path,locale,extension)
|
54
|
+
ext = extension || '.html.erb'
|
55
|
+
dict = ReadyForI18N::LocaleDictionary.new(locale)
|
56
|
+
Dir.glob(File.join(src_path,"**/*#{ext}")).each do |f|
|
57
|
+
full_target_path = File.dirname(f).gsub(src_path,target_path)
|
58
|
+
FileUtils.makedirs full_target_path
|
59
|
+
target_file = File.join(full_target_path,File.basename(f))
|
60
|
+
ReadyForI18N::LabelExtractor.new(f,target_file).extract{|k,v| dict[k] = v}
|
61
|
+
ReadyForI18N::TextExtractor.new(target_file,target_file).extract{|k,v| dict[k] = v}
|
62
|
+
puts "i18n ready: #{target_file}"
|
63
|
+
end
|
64
|
+
locale_file = dict.write_to target_path
|
65
|
+
puts "------------------------------------------------------------------------------"
|
66
|
+
puts "Locale file: #{locale_file}"
|
67
|
+
end
|
68
|
+
|
69
|
+
# Run the i18n generating
|
70
|
+
excute(options['source'],options['destination'],options['locale'],options['extension'])
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ReadyForI18N
|
2
|
+
module BaseExtractor
|
3
|
+
def initialize(erb_source, erb_target = nil)
|
4
|
+
@erb_source = erb_source
|
5
|
+
@erb_target = erb_target
|
6
|
+
end
|
7
|
+
|
8
|
+
def extract
|
9
|
+
buffer = ''
|
10
|
+
File.open(@erb_source).each do |line|
|
11
|
+
unless skip_line?(line)
|
12
|
+
values_in_line(line).each do |e|
|
13
|
+
if to_value(e).size > 1
|
14
|
+
yield(to_key(e),to_value(e)) if block_given?
|
15
|
+
replace_line(line,e)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
buffer << line
|
20
|
+
end
|
21
|
+
File.open(@erb_target,'w+') {|f| f << buffer} if @erb_target
|
22
|
+
end
|
23
|
+
def to_key(s)
|
24
|
+
result = to_value(s).scan(/\w+/).join('_').downcase
|
25
|
+
key_prefix ? "#{key_prefix}_#{result}" : result
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'ready_for_i18n'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module ReadyForI18N
|
5
|
+
class I18nAutomator
|
6
|
+
def self.run(src_erb_path,target_erb_path,locale_path,locale)
|
7
|
+
dict = ReadyForI18N::LocaleDictionary.new(locale)
|
8
|
+
Dir.glob(File.join(src_erb_path,'**/*.html.erb')).each do |f|
|
9
|
+
target_path = File.dirname(f).gsub(src_erb_path,target_erb_path)
|
10
|
+
FileUtils.makedirs target_path
|
11
|
+
target_file = File.join(target_path,File.basename(f))
|
12
|
+
ReadyForI18N::LabelExtractor.new(f,target_file).extract{|k,v| dict[k] = v}
|
13
|
+
ReadyForI18N::TextExtractor.new(target_file,target_file).extract{|k,v| dict[k] = v}
|
14
|
+
end
|
15
|
+
dict.write_to locale_path
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
srcpath = "/Users/zig/workspace/sonar/tags/1.12/sonar-web/src/main/webapp/WEB-INF/app/views"
|
22
|
+
ReadyForI18N::I18nAutomator.run(srcpath,'/tmp','/tmp','en')
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ReadyForI18N
|
2
|
+
class LabelExtractor
|
3
|
+
LABEL_IN_HELPER_PATTERN = %w{label_tag link_to field_set_tag}.map{|h| /#{h}[\s\w_]*('|")([\w ]*)(\1)/ }
|
4
|
+
|
5
|
+
include ReadyForI18N::BaseExtractor
|
6
|
+
|
7
|
+
protected
|
8
|
+
def values_in_line(line)
|
9
|
+
LABEL_IN_HELPER_PATTERN.map{|h| line.match(h).captures.join if line =~ h}.compact
|
10
|
+
end
|
11
|
+
def skip_line?(s)
|
12
|
+
false
|
13
|
+
end
|
14
|
+
def to_value(s)
|
15
|
+
s.strip[1..-2]
|
16
|
+
end
|
17
|
+
def replace_line(line,e)
|
18
|
+
line.gsub!(e,"t(:#{to_key(e)})")
|
19
|
+
end
|
20
|
+
def key_prefix
|
21
|
+
'label'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ReadyForI18N
|
2
|
+
class LocaleDictionary
|
3
|
+
def initialize(locale = nil)
|
4
|
+
@locale = locale || 'en'
|
5
|
+
@hash = {}
|
6
|
+
end
|
7
|
+
def []=(key,value)
|
8
|
+
@hash[key] = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def write_to(path)
|
12
|
+
file = File.join(path,"#{@locale}.yml")
|
13
|
+
File.open(file,'w+') do |f|
|
14
|
+
f.puts "#{@locale}:"
|
15
|
+
@hash.keys.sort{|a,b|a.to_s<=>b.to_s}.each { |k| f.puts " #{k}: \"#{@hash[k]}\"" }
|
16
|
+
end
|
17
|
+
file
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module ReadyForI18N
|
2
|
+
class TextExtractor
|
3
|
+
SKIP_TAGS = [[/<script/i,/<\/script>/i],[/<%/,/%>/],[/<style/i,/\/style>/i]]
|
4
|
+
SKIP_INLINE_TAG = [/<%(.*?)%>/,/<(.*?)>/,/<%(.*)$/,/^(.*)%>/,/ /,/»/]
|
5
|
+
SEPERATOR = '_@@@_'
|
6
|
+
|
7
|
+
include ReadyForI18N::BaseExtractor
|
8
|
+
|
9
|
+
protected
|
10
|
+
def values_in_line(line)
|
11
|
+
SKIP_INLINE_TAG.inject(line.clone){|memo,tag| memo.gsub(tag,SEPERATOR)}.strip.split SEPERATOR
|
12
|
+
end
|
13
|
+
def skip_line?(s)
|
14
|
+
@stack ||= []
|
15
|
+
return true if s.nil? || s.strip.size == 0
|
16
|
+
jump_in_tag = SKIP_TAGS.find{ |start_tag,end_tag| s =~ start_tag}
|
17
|
+
@stack.push jump_in_tag[1] if jump_in_tag
|
18
|
+
if @stack.last
|
19
|
+
end_tag_match = s.match(@stack.last)
|
20
|
+
if end_tag_match
|
21
|
+
@stack.pop
|
22
|
+
return skip_line?(end_tag_match.post_match)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
return !@stack.empty?
|
26
|
+
end
|
27
|
+
def to_value(s)
|
28
|
+
s.strip
|
29
|
+
end
|
30
|
+
def replace_line(line,e)
|
31
|
+
line.gsub!(e,"<%=t(:#{to_key(e)})%>")
|
32
|
+
end
|
33
|
+
def key_prefix
|
34
|
+
'text'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,74 @@
|
|
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{ready_for_i18n}
|
8
|
+
s.version = "0.2.2"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["zigzag"]
|
12
|
+
s.date = %q{2009-12-15}
|
13
|
+
s.default_executable = %q{ready_for_i18n}
|
14
|
+
s.description = %q{ ready_for_i18n will help you extract visible hard-coded text from your ERB view files,
|
15
|
+
then choose a proper key and replace them with the I18n.translate method like t(:login)
|
16
|
+
}
|
17
|
+
s.email = %q{zigzag.chen@gmail.com}
|
18
|
+
s.executables = ["ready_for_i18n"]
|
19
|
+
s.extra_rdoc_files = [
|
20
|
+
"LICENSE",
|
21
|
+
"README.rdoc"
|
22
|
+
]
|
23
|
+
s.files = [
|
24
|
+
".document",
|
25
|
+
".gitignore",
|
26
|
+
"LICENSE",
|
27
|
+
"README.rdoc",
|
28
|
+
"Rakefile",
|
29
|
+
"VERSION",
|
30
|
+
"bin/ready_for_i18n",
|
31
|
+
"lib/base_extractor.rb",
|
32
|
+
"lib/i18n_automator.rb",
|
33
|
+
"lib/label_extractor.rb",
|
34
|
+
"lib/locale_dictionary.rb",
|
35
|
+
"lib/ready_for_i18n.rb",
|
36
|
+
"lib/text_extractor.rb",
|
37
|
+
"ready_for_i18n.gemspec",
|
38
|
+
"test/fixtures/index.html.erb",
|
39
|
+
"test/helper.rb",
|
40
|
+
"test/output/en.yml",
|
41
|
+
"test/output/label.html.erb",
|
42
|
+
"test/output/text.html.erb",
|
43
|
+
"test/test_base_extractor.rb",
|
44
|
+
"test/test_label_extractor.rb",
|
45
|
+
"test/test_locale_dictionary.rb",
|
46
|
+
"test/test_text_extrator.rb"
|
47
|
+
]
|
48
|
+
s.homepage = %q{http://github.com/zigzag/ready_for_i18n}
|
49
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
50
|
+
s.require_paths = ["lib"]
|
51
|
+
s.rubygems_version = %q{1.3.5}
|
52
|
+
s.summary = %q{ready_for_i18n is a tool helping for the very first step of transfering your local Rails project to an i18n one.}
|
53
|
+
s.test_files = [
|
54
|
+
"test/helper.rb",
|
55
|
+
"test/test_base_extractor.rb",
|
56
|
+
"test/test_label_extractor.rb",
|
57
|
+
"test/test_locale_dictionary.rb",
|
58
|
+
"test/test_text_extrator.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
|
+
s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
67
|
+
else
|
68
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
69
|
+
end
|
70
|
+
else
|
71
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
@@ -0,0 +1,89 @@
|
|
1
|
+
<table width="100%">
|
2
|
+
<tr>
|
3
|
+
<td valign="top">
|
4
|
+
<h1>Users</h1>
|
5
|
+
<br/>
|
6
|
+
<table class="data sortable" id="users">
|
7
|
+
<thead>
|
8
|
+
<tr>
|
9
|
+
<th class="left">Login</th>
|
10
|
+
<th class="left">Name</th>
|
11
|
+
<th class="left nosort">Groups</th>
|
12
|
+
<th class="left nosort" nowrap>Operations</th>
|
13
|
+
</tr>
|
14
|
+
</thead>
|
15
|
+
<tbody >
|
16
|
+
<% @users.each do |user|%>
|
17
|
+
<% clazz = cycle("even", "odd", :name => 'index_user') %>
|
18
|
+
<tr id="user-<%= u user.login -%>">
|
19
|
+
<td class="left" valign="top"><%=user.login %></td>
|
20
|
+
<td class="left" valign="top"><%=user.name %></td>
|
21
|
+
<td class="left" valign="top">
|
22
|
+
<%= user.groups.sort.map(&:name).join(', ') %> (<%= link_to "select", {:action => 'select_group', :id => user.id}, :id => "select-#{u user.login}" %>)
|
23
|
+
</td>
|
24
|
+
<td class="left" valign="top">
|
25
|
+
<%= link_to "edit", { :id => user.id, :action => 'edit'}, :id => "edit-#{u user.login}" %> |
|
26
|
+
<%= link_to "delete", {:action => 'destroy', :id => user.id}, {:confirm => "Warning : are you sure to delete this user ?", :method => 'delete', :id => "delete-#{u user.login}"} %>
|
27
|
+
</td>
|
28
|
+
</tr>
|
29
|
+
<% end %>
|
30
|
+
</tbody>
|
31
|
+
</table>
|
32
|
+
</td>
|
33
|
+
<td class="sep"> </td>
|
34
|
+
<td valign="top" align="right" width="210">
|
35
|
+
<%
|
36
|
+
action_name = 'create'
|
37
|
+
title='Add new user'
|
38
|
+
if @user.id
|
39
|
+
action_name = 'update'
|
40
|
+
title='Edit user'
|
41
|
+
end
|
42
|
+
%>
|
43
|
+
<% form_for :user, @user, :url => { :id => @user.id, :action => action_name}, :html => { :method => @user.id.nil?? :post : :put } do |f| %>
|
44
|
+
<table class="admintable" width="100%">
|
45
|
+
<tr>
|
46
|
+
<td class="left" valign="top"><h1><%= title %></h1></td>
|
47
|
+
</tr>
|
48
|
+
<tr>
|
49
|
+
<td class="left" valign="top">Login:
|
50
|
+
<% if @user.id %>
|
51
|
+
<%= @user.login %>
|
52
|
+
<%= f.hidden_field :login %>
|
53
|
+
|
54
|
+
<% else %>
|
55
|
+
<br/><%= f.text_field :login, :size => 30, :maxLength => 40 %>
|
56
|
+
<% end %>
|
57
|
+
</td>
|
58
|
+
</tr>
|
59
|
+
<tr>
|
60
|
+
<td class="left" valign="top">Name:<br/><%= f.text_field :name, :size => 30, :maxLength => 200 %></td>
|
61
|
+
</tr>
|
62
|
+
<tr>
|
63
|
+
<td class="left" valign="top">Password:<br/><%= f.password_field :password, :size => 30, :maxLength => 50 %></td>
|
64
|
+
</tr>
|
65
|
+
<tr>
|
66
|
+
<td class="left" valign="top">Confirm password:<br/><%= f.password_field :password_confirmation, :size => 30, :maxLength => 50 %></td>
|
67
|
+
</tr>
|
68
|
+
<tr>
|
69
|
+
<td class="left" nowrap="nowrap" valign="top" colspan="2">
|
70
|
+
<%= submit_tag @user.id.nil?? 'Create':'Update' %>
|
71
|
+
<%= link_to 'cancel', { :controller => 'users', :action => 'index'}, { :class => 'action' } %><br/>
|
72
|
+
</td>
|
73
|
+
</tr>
|
74
|
+
|
75
|
+
</table>
|
76
|
+
<% end %>
|
77
|
+
</td>
|
78
|
+
</tr>
|
79
|
+
</table>
|
80
|
+
|
81
|
+
<%= link_to "export",
|
82
|
+
url_for(:controller => 'api/rules', :action => 'index', :language => @profile.language, :profile => @profile.name,
|
83
|
+
:plugins => @plugins.join(','),
|
84
|
+
:status => @status, :searchtext => @searchtext, :priorities => @priorities.join(','), :categories => @categories.join(','),
|
85
|
+
:format => 'csv'),
|
86
|
+
:class => 'action' %> Export
|
87
|
+
|
88
|
+
<%= link_to_remote 'Add Event', {:url => { :controller => 'events', :action => "new", :rid => params['rid'] },
|
89
|
+
:update => "event_form"}, {:class => 'action'} %>
|
data/test/helper.rb
ADDED
data/test/output/en.yml
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
<table width="100%">
|
2
|
+
<tr>
|
3
|
+
<td valign="top">
|
4
|
+
<h1>Users</h1>
|
5
|
+
<br/>
|
6
|
+
<table class="data sortable" id="users">
|
7
|
+
<thead>
|
8
|
+
<tr>
|
9
|
+
<th class="left">Login</th>
|
10
|
+
<th class="left">Name</th>
|
11
|
+
<th class="left nosort">Groups</th>
|
12
|
+
<th class="left nosort" nowrap>Operations</th>
|
13
|
+
</tr>
|
14
|
+
</thead>
|
15
|
+
<tbody >
|
16
|
+
<% @users.each do |user|%>
|
17
|
+
<% clazz = cycle("even", "odd", :name => 'index_user') %>
|
18
|
+
<tr id="user-<%= u user.login -%>">
|
19
|
+
<td class="left" valign="top"><%=user.login %></td>
|
20
|
+
<td class="left" valign="top"><%=user.name %></td>
|
21
|
+
<td class="left" valign="top">
|
22
|
+
<%= user.groups.sort.map(&:name).join(', ') %> (<%= link_to t(:label_select), {:action => 'select_group', :id => user.id}, :id => "select-#{u user.login}" %>)
|
23
|
+
</td>
|
24
|
+
<td class="left" valign="top">
|
25
|
+
<%= link_to t(:label_edit), { :id => user.id, :action => 'edit'}, :id => "edit-#{u user.login}" %> |
|
26
|
+
<%= link_to t(:label_delete), {:action => 'destroy', :id => user.id}, {:confirm => "Warning : are you sure to delete this user ?", :method => 'delete', :id => "delete-#{u user.login}"} %>
|
27
|
+
</td>
|
28
|
+
</tr>
|
29
|
+
<% end %>
|
30
|
+
</tbody>
|
31
|
+
</table>
|
32
|
+
</td>
|
33
|
+
<td class="sep"> </td>
|
34
|
+
<td valign="top" align="right" width="210">
|
35
|
+
<%
|
36
|
+
action_name = 'create'
|
37
|
+
title='Add new user'
|
38
|
+
if @user.id
|
39
|
+
action_name = 'update'
|
40
|
+
title='Edit user'
|
41
|
+
end
|
42
|
+
%>
|
43
|
+
<% form_for :user, @user, :url => { :id => @user.id, :action => action_name}, :html => { :method => @user.id.nil?? :post : :put } do |f| %>
|
44
|
+
<table class="admintable" width="100%">
|
45
|
+
<tr>
|
46
|
+
<td class="left" valign="top"><h1><%= title %></h1></td>
|
47
|
+
</tr>
|
48
|
+
<tr>
|
49
|
+
<td class="left" valign="top">Login:
|
50
|
+
<% if @user.id %>
|
51
|
+
<%= @user.login %>
|
52
|
+
<%= f.hidden_field :login %>
|
53
|
+
|
54
|
+
<% else %>
|
55
|
+
<br/><%= f.text_field :login, :size => 30, :maxLength => 40 %>
|
56
|
+
<% end %>
|
57
|
+
</td>
|
58
|
+
</tr>
|
59
|
+
<tr>
|
60
|
+
<td class="left" valign="top">Name:<br/><%= f.text_field :name, :size => 30, :maxLength => 200 %></td>
|
61
|
+
</tr>
|
62
|
+
<tr>
|
63
|
+
<td class="left" valign="top">Password:<br/><%= f.password_field :password, :size => 30, :maxLength => 50 %></td>
|
64
|
+
</tr>
|
65
|
+
<tr>
|
66
|
+
<td class="left" valign="top">Confirm password:<br/><%= f.password_field :password_confirmation, :size => 30, :maxLength => 50 %></td>
|
67
|
+
</tr>
|
68
|
+
<tr>
|
69
|
+
<td class="left" nowrap="nowrap" valign="top" colspan="2">
|
70
|
+
<%= submit_tag @user.id.nil?? 'Create':'Update' %>
|
71
|
+
<%= link_to t(:label_cancel), { :controller => 'users', :action => 'index'}, { :class => 'action' } %><br/>
|
72
|
+
</td>
|
73
|
+
</tr>
|
74
|
+
|
75
|
+
</table>
|
76
|
+
<% end %>
|
77
|
+
</td>
|
78
|
+
</tr>
|
79
|
+
</table>
|
80
|
+
|
81
|
+
<%= link_to t(:label_export),
|
82
|
+
url_for(:controller => 'api/rules', :action => 'index', :language => @profile.language, :profile => @profile.name,
|
83
|
+
:plugins => @plugins.join(','),
|
84
|
+
:status => @status, :searchtext => @searchtext, :priorities => @priorities.join(','), :categories => @categories.join(','),
|
85
|
+
:format => 'csv'),
|
86
|
+
:class => 'action' %> Export
|
87
|
+
|
88
|
+
<%= link_to_remote t(:label_add_event), {:url => { :controller => 'events', :action => "new", :rid => params['rid'] },
|
89
|
+
:update => "event_form"}, {:class => 'action'} %>
|
@@ -0,0 +1,89 @@
|
|
1
|
+
<table width="100%">
|
2
|
+
<tr>
|
3
|
+
<td valign="top">
|
4
|
+
<h1><%=t(:text_users)%></h1>
|
5
|
+
<br/>
|
6
|
+
<table class="data sortable" id="users">
|
7
|
+
<thead>
|
8
|
+
<tr>
|
9
|
+
<th class="left"><%=t(:text_login)%></th>
|
10
|
+
<th class="left"><%=t(:text_name)%></th>
|
11
|
+
<th class="left nosort"><%=t(:text_groups)%></th>
|
12
|
+
<th class="left nosort" nowrap><%=t(:text_operations)%></th>
|
13
|
+
</tr>
|
14
|
+
</thead>
|
15
|
+
<tbody >
|
16
|
+
<% @users.each do |user|%>
|
17
|
+
<% clazz = cycle("even", "odd", :name => 'index_user') %>
|
18
|
+
<tr id="user-<%= u user.login -%>">
|
19
|
+
<td class="left" valign="top"><%=user.login %></td>
|
20
|
+
<td class="left" valign="top"><%=user.name %></td>
|
21
|
+
<td class="left" valign="top">
|
22
|
+
<%= user.groups.sort.map(&:name).join(', ') %> (<%= link_to "select", {:action => 'select_group', :id => user.id}, :id => "select-#{u user.login}" %>)
|
23
|
+
</td>
|
24
|
+
<td class="left" valign="top">
|
25
|
+
<%= link_to "edit", { :id => user.id, :action => 'edit'}, :id => "edit-#{u user.login}" %> |
|
26
|
+
<%= link_to "delete", {:action => 'destroy', :id => user.id}, {:confirm => "Warning : are you sure to delete this user ?", :method => 'delete', :id => "delete-#{u user.login}"} %>
|
27
|
+
</td>
|
28
|
+
</tr>
|
29
|
+
<% end %>
|
30
|
+
</tbody>
|
31
|
+
</table>
|
32
|
+
</td>
|
33
|
+
<td class="sep"> </td>
|
34
|
+
<td valign="top" align="right" width="210">
|
35
|
+
<%
|
36
|
+
action_name = 'create'
|
37
|
+
title='Add new user'
|
38
|
+
if @user.id
|
39
|
+
action_name = 'update'
|
40
|
+
title='Edit user'
|
41
|
+
end
|
42
|
+
%>
|
43
|
+
<% form_for :user, @user, :url => { :id => @user.id, :action => action_name}, :html => { :method => @user.id.nil?? :post : :put } do |f| %>
|
44
|
+
<table class="admintable" width="100%">
|
45
|
+
<tr>
|
46
|
+
<td class="left" valign="top"><h1><%= title %></h1></td>
|
47
|
+
</tr>
|
48
|
+
<tr>
|
49
|
+
<td class="left" valign="top"><%=t(:text_login)%>
|
50
|
+
<% if @user.id %>
|
51
|
+
<%= @user.login %>
|
52
|
+
<%= f.hidden_field :login %>
|
53
|
+
|
54
|
+
<% else %>
|
55
|
+
<br/><%= f.text_field :login, :size => 30, :maxLength => 40 %>
|
56
|
+
<% end %>
|
57
|
+
</td>
|
58
|
+
</tr>
|
59
|
+
<tr>
|
60
|
+
<td class="left" valign="top"><%=t(:text_name)%><br/><%= f.text_field :name, :size => 30, :maxLength => 200 %></td>
|
61
|
+
</tr>
|
62
|
+
<tr>
|
63
|
+
<td class="left" valign="top"><%=t(:text_password)%><br/><%= f.password_field :password, :size => 30, :maxLength => 50 %></td>
|
64
|
+
</tr>
|
65
|
+
<tr>
|
66
|
+
<td class="left" valign="top"><%=t(:text_confirm_password)%><br/><%= f.password_field :password_confirmation, :size => 30, :maxLength => 50 %></td>
|
67
|
+
</tr>
|
68
|
+
<tr>
|
69
|
+
<td class="left" nowrap="nowrap" valign="top" colspan="2">
|
70
|
+
<%= submit_tag @user.id.nil?? 'Create':'Update' %>
|
71
|
+
<%= link_to 'cancel', { :controller => 'users', :action => 'index'}, { :class => 'action' } %><br/>
|
72
|
+
</td>
|
73
|
+
</tr>
|
74
|
+
|
75
|
+
</table>
|
76
|
+
<% end %>
|
77
|
+
</td>
|
78
|
+
</tr>
|
79
|
+
</table>
|
80
|
+
|
81
|
+
<%= link_to "export",
|
82
|
+
url_for(:controller => 'api/rules', :action => 'index', :language => @profile.language, :profile => @profile.name,
|
83
|
+
:plugins => @plugins.join(','),
|
84
|
+
:status => @status, :searchtext => @searchtext, :priorities => @priorities.join(','), :categories => @categories.join(','),
|
85
|
+
:format => 'csv'),
|
86
|
+
:class => 'action' %> <%=t(:text_export)%>
|
87
|
+
|
88
|
+
<%= link_to_remote 'Add Event', {:url => { :controller => 'events', :action => "new", :rid => params['rid'] },
|
89
|
+
:update => "event_form"}, {:class => 'action'} %>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestBaseExtractor < Test::Unit::TestCase
|
4
|
+
should "find a proper key for a given text/label" do
|
5
|
+
c = Object.new
|
6
|
+
def c.key_prefix; nil;end
|
7
|
+
def c.to_value(s); s ;end
|
8
|
+
c.extend ReadyForI18N::BaseExtractor
|
9
|
+
assert_equal('confirm_password', c.to_key('Confirm password:'))
|
10
|
+
end
|
11
|
+
|
12
|
+
should "work fine with prefix" do
|
13
|
+
c = Object.new
|
14
|
+
def c.key_prefix; 'label' ;end
|
15
|
+
def c.to_value(s); s ;end
|
16
|
+
c.extend ReadyForI18N::BaseExtractor
|
17
|
+
assert_equal('label_login', c.to_key('Login:'))
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestLabelExtractor < Test::Unit::TestCase
|
4
|
+
should "extract the label that need i18n from the erb view file" do
|
5
|
+
f = File.join(File.dirname(__FILE__),'fixtures','index.html.erb')
|
6
|
+
result = []
|
7
|
+
ReadyForI18N::LabelExtractor.new(f).extract{|k,v| result << v}
|
8
|
+
expected = %w{edit delete select export cancel} << "Add Event"
|
9
|
+
assert_same_elements(expected,result)
|
10
|
+
end
|
11
|
+
|
12
|
+
should "replace the label in helper with t method" do
|
13
|
+
source = File.join(File.dirname(__FILE__),'fixtures','index.html.erb')
|
14
|
+
target = File.join(File.dirname(__FILE__),'output','label.html.erb')
|
15
|
+
ReadyForI18N::LabelExtractor.new(source,target).extract
|
16
|
+
expected = %w{edit delete select export cancel add_event}
|
17
|
+
expected.each do |e|
|
18
|
+
assert(File.read(target).include?("t(:label_#{e})"), "should found t method with symbol")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestLocaleDictionary < Test::Unit::TestCase
|
4
|
+
should "save the result hash to yaml file" do
|
5
|
+
target_path = File.join(File.dirname(__FILE__),'output')
|
6
|
+
dict = ReadyForI18N::LocaleDictionary.new
|
7
|
+
dict['login_key'] = 'Login:'
|
8
|
+
dict['label'] = 'OK'
|
9
|
+
dict['text'] = 'Please Confirm:'
|
10
|
+
dict.write_to target_path
|
11
|
+
|
12
|
+
result = YAML.load_file File.join(target_path,'en.yml')
|
13
|
+
assert_equal('Login:', result['en']['login_key'])
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestTextExtractor < Test::Unit::TestCase
|
4
|
+
should "extract the text that need i18n from the erb view file" do
|
5
|
+
f = File.join(File.dirname(__FILE__),'fixtures','index.html.erb')
|
6
|
+
expected = %w{Users Login Name Groups Operations Login: Name: Password: Export} << 'Confirm password:'
|
7
|
+
result = []
|
8
|
+
ReadyForI18N::TextExtractor.new(f).extract{|k,v| result << v}
|
9
|
+
assert_same_elements(expected,result)
|
10
|
+
end
|
11
|
+
|
12
|
+
should "replace the text in helper with t method" do
|
13
|
+
source = File.join(File.dirname(__FILE__),'fixtures','index.html.erb')
|
14
|
+
target = File.join(File.dirname(__FILE__),'output','text.html.erb')
|
15
|
+
ReadyForI18N::TextExtractor.new(source,target).extract
|
16
|
+
%w{Users Login Name Groups Operations Login: Name: Password: Export}.each do |e|
|
17
|
+
assert(File.read(target).include?("<%=t(:text_#{e.downcase.gsub(':','')})%>"), "should found t method with symbol")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ready_for_i18n
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- zigzag
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-15 00:00:00 +08:00
|
13
|
+
default_executable: ready_for_i18n
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: thoughtbot-shoulda
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
description: " ready_for_i18n will help you extract visible hard-coded text from your ERB view files,\n then choose a proper key and replace them with the I18n.translate method like t(:login)\n"
|
26
|
+
email: zigzag.chen@gmail.com
|
27
|
+
executables:
|
28
|
+
- ready_for_i18n
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- LICENSE
|
33
|
+
- README.rdoc
|
34
|
+
files:
|
35
|
+
- .document
|
36
|
+
- .gitignore
|
37
|
+
- LICENSE
|
38
|
+
- README.rdoc
|
39
|
+
- Rakefile
|
40
|
+
- VERSION
|
41
|
+
- bin/ready_for_i18n
|
42
|
+
- lib/base_extractor.rb
|
43
|
+
- lib/i18n_automator.rb
|
44
|
+
- lib/label_extractor.rb
|
45
|
+
- lib/locale_dictionary.rb
|
46
|
+
- lib/ready_for_i18n.rb
|
47
|
+
- lib/text_extractor.rb
|
48
|
+
- ready_for_i18n.gemspec
|
49
|
+
- test/fixtures/index.html.erb
|
50
|
+
- test/helper.rb
|
51
|
+
- test/output/en.yml
|
52
|
+
- test/output/label.html.erb
|
53
|
+
- test/output/text.html.erb
|
54
|
+
- test/test_base_extractor.rb
|
55
|
+
- test/test_label_extractor.rb
|
56
|
+
- test/test_locale_dictionary.rb
|
57
|
+
- test/test_text_extrator.rb
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: http://github.com/zigzag/ready_for_i18n
|
60
|
+
licenses: []
|
61
|
+
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options:
|
64
|
+
- --charset=UTF-8
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
version:
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
requirements: []
|
80
|
+
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.3.5
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: ready_for_i18n is a tool helping for the very first step of transfering your local Rails project to an i18n one.
|
86
|
+
test_files:
|
87
|
+
- test/helper.rb
|
88
|
+
- test/test_base_extractor.rb
|
89
|
+
- test/test_label_extractor.rb
|
90
|
+
- test/test_locale_dictionary.rb
|
91
|
+
- test/test_text_extrator.rb
|