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