i18n_generators 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/.gitignore +1 -0
  2. data/History.txt +104 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +104 -0
  5. data/Rakefile +38 -0
  6. data/VERSION +1 -0
  7. data/generators/i18n/USAGE +13 -0
  8. data/generators/i18n/i18n_generator.rb +85 -0
  9. data/generators/i18n/lib/yaml.rb +187 -0
  10. data/generators/i18n/templates/base.yml +0 -0
  11. data/generators/i18n/templates/i18n_config.rb +5 -0
  12. data/generators/i18n/templates/translation.yml +1 -0
  13. data/generators/i18n_locale/USAGE +12 -0
  14. data/generators/i18n_locale/i18n_locale_command.rb +135 -0
  15. data/generators/i18n_locale/i18n_locale_generator.rb +9 -0
  16. data/generators/i18n_locale/lib/cldr.rb +139 -0
  17. data/generators/i18n_scaffold/i18n_scaffold_generator.rb +3 -0
  18. data/generators/i18n_scaffold/templates/controller.rb +85 -0
  19. data/generators/i18n_scaffold/templates/functional_test.rb +45 -0
  20. data/generators/i18n_scaffold/templates/helper.rb +2 -0
  21. data/generators/i18n_scaffold/templates/helper_test.rb +4 -0
  22. data/generators/i18n_scaffold/templates/layout.html.erb +17 -0
  23. data/generators/i18n_scaffold/templates/style.css +54 -0
  24. data/generators/i18n_scaffold/templates/view_edit.html.erb +18 -0
  25. data/generators/i18n_scaffold/templates/view_index.html.erb +24 -0
  26. data/generators/i18n_scaffold/templates/view_new.html.erb +17 -0
  27. data/generators/i18n_scaffold/templates/view_show.html.erb +10 -0
  28. data/generators/i18n_translation/USAGE +9 -0
  29. data/generators/i18n_translation/i18n_translation_command.rb +121 -0
  30. data/generators/i18n_translation/i18n_translation_generator.rb +9 -0
  31. data/generators/i18n_translation/lib/erb_executer.rb +31 -0
  32. data/generators/i18n_translation/lib/recording_backend.rb +16 -0
  33. data/generators/i18n_translation/lib/through_ryoku.rb +8 -0
  34. data/generators/i18n_translation/lib/translator.rb +28 -0
  35. data/i18n_generators.gemspec +87 -0
  36. data/spec/cldr_spec.rb +54 -0
  37. data/spec/data/cldr/ja.html +3112 -0
  38. data/spec/data/yml/active_record/en-US.yml +54 -0
  39. data/spec/i18n_locale_command_spec.rb +63 -0
  40. data/spec/i18n_translation_command_spec.rb +24 -0
  41. data/spec/spec_helper.rb +39 -0
  42. data/spec/translator_spec.rb +46 -0
  43. data/spec/yaml_spec.rb +59 -0
  44. metadata +114 -0
@@ -0,0 +1,2 @@
1
+ module <%= controller_class_name %>Helper
2
+ end
@@ -0,0 +1,4 @@
1
+ require 'test_helper'
2
+
3
+ class <%= controller_class_name %>HelperTest < ActionView::TestCase
4
+ end
@@ -0,0 +1,17 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
+ <head>
6
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
7
+ <title><%= controller_class_name %>: <%%= controller.action_name %></title>
8
+ <%%= stylesheet_link_tag 'scaffold' %>
9
+ </head>
10
+ <body>
11
+
12
+ <p style="color: green"><%%= flash[:notice] %></p>
13
+
14
+ <%%= yield %>
15
+
16
+ </body>
17
+ </html>
@@ -0,0 +1,54 @@
1
+ body { background-color: #fff; color: #333; }
2
+
3
+ body, p, ol, ul, td {
4
+ font-family: verdana, arial, helvetica, sans-serif;
5
+ font-size: 13px;
6
+ line-height: 18px;
7
+ }
8
+
9
+ pre {
10
+ background-color: #eee;
11
+ padding: 10px;
12
+ font-size: 11px;
13
+ }
14
+
15
+ a { color: #000; }
16
+ a:visited { color: #666; }
17
+ a:hover { color: #fff; background-color:#000; }
18
+
19
+ .fieldWithErrors {
20
+ padding: 2px;
21
+ background-color: red;
22
+ display: table;
23
+ }
24
+
25
+ #errorExplanation {
26
+ width: 400px;
27
+ border: 2px solid red;
28
+ padding: 7px;
29
+ padding-bottom: 12px;
30
+ margin-bottom: 20px;
31
+ background-color: #f0f0f0;
32
+ }
33
+
34
+ #errorExplanation h2 {
35
+ text-align: left;
36
+ font-weight: bold;
37
+ padding: 5px 5px 5px 15px;
38
+ font-size: 12px;
39
+ margin: -7px;
40
+ background-color: #c00;
41
+ color: #fff;
42
+ }
43
+
44
+ #errorExplanation p {
45
+ color: #333;
46
+ margin-bottom: 0;
47
+ padding: 5px;
48
+ }
49
+
50
+ #errorExplanation ul li {
51
+ font-size: 12px;
52
+ list-style: square;
53
+ }
54
+
@@ -0,0 +1,18 @@
1
+ <h1><%% translate(:editing, :default => "Editing {{model}}", :model => <%= class_name %>.human_name, :scope => [:railties, :scaffold]) %></h1>
2
+
3
+ <%% form_for(@<%= singular_name %>) do |f| %>
4
+ <%%= f.error_messages %>
5
+
6
+ <% for attribute in attributes -%>
7
+ <p>
8
+ <%%= f.label :<%= attribute.name %> %><br />
9
+ <%%= f.<%= attribute.field_type %> :<%= attribute.name %> %>
10
+ </p>
11
+ <% end -%>
12
+ <p>
13
+ <%%= f.submit translate(:update, :default => "Update", :scope => [:railties, :scaffold]) %>
14
+ </p>
15
+ <%% end %>
16
+
17
+ <%%= link_to translate(:show, :default => 'Show', :scope => [:railties, :scaffold]), @<%= singular_name %> %> |
18
+ <%%= link_to translate(:back, :default => 'Back', :scope => [:railties, :scaffold]), <%= plural_name %>_path %>
@@ -0,0 +1,24 @@
1
+ <h1><%%= translate(:listing, :default => "Listing {{model}}", :model => <%= class_name %>.human_name(:count => @<%= plural_name %>.size), :count => @<%= plural_name %>.size, :scope => [:railties, :scaffold]) %></h1>
2
+
3
+ <table>
4
+ <tr>
5
+ <% for attribute in attributes -%>
6
+ <th><%%= <%= class_name %>.human_attribute_name('<%= attribute.column.name %>') %></th>
7
+ <% end -%>
8
+ </tr>
9
+
10
+ <%% for <%= singular_name %> in @<%= plural_name %> %>
11
+ <tr>
12
+ <% for attribute in attributes -%>
13
+ <td><%%=h <%= singular_name %>.<%= attribute.name %> %></td>
14
+ <% end -%>
15
+ <td><%%= link_to translate(:show, :default => 'Show', :scope => [:railties, :scaffold]), <%= singular_name %> %></td>
16
+ <td><%%= link_to translate(:edit, :default => 'Edit', :scope => [:railties, :scaffold]), edit_<%= singular_name %>_path(<%= singular_name %>) %></td>
17
+ <td><%%= link_to translate(:destroy, :default => 'Destroy', :scope => [:railties, :scaffold]), <%= singular_name %>, :confirm => translate(:confirmation, :default => 'Are you sure?', :scope => [:railties, :scaffold]), :method => :delete %></td>
18
+ </tr>
19
+ <%% end %>
20
+ </table>
21
+
22
+ <br />
23
+
24
+ <%%= link_to translate(:new, :default => "New {{model}}", :model => <%= class_name %>.human_name, :scope => [:railties, :scaffold]), new_<%= singular_name %>_path %>
@@ -0,0 +1,17 @@
1
+ <h1><%%= translate(:new, :default => "New {{model}}", :model => <%= class_name %>.human_name, :scope => [:railties, :scaffold]) %></h1>
2
+
3
+ <%% form_for(@<%= singular_name %>) do |f| %>
4
+ <%%= f.error_messages %>
5
+
6
+ <% for attribute in attributes -%>
7
+ <p>
8
+ <%%= f.label :<%= attribute.name %> %><br />
9
+ <%%= f.<%= attribute.field_type %> :<%= attribute.name %> %>
10
+ </p>
11
+ <% end -%>
12
+ <p>
13
+ <%%= f.submit translate(:create, :default => "Create", :scope => [:railties, :scaffold]) %>
14
+ </p>
15
+ <%% end %>
16
+
17
+ <%%= link_to translate(:back, :default => 'Back', :scope => [:railties, :scaffold]), <%= plural_name %>_path %>
@@ -0,0 +1,10 @@
1
+ <% for attribute in attributes -%>
2
+ <p>
3
+ <b><%%= <%= class_name %>.human_attribute_name('<%= attribute.column.name %>') %>:</b>
4
+ <%%=h @<%= singular_name %>.<%= attribute.name %> %>
5
+ </p>
6
+
7
+ <% end -%>
8
+
9
+ <%%= link_to translate(:edit, :default => 'Edit', :scope => [:railties, :scaffold]), edit_<%= singular_name %>_path(@<%= singular_name %>) %> |
10
+ <%%= link_to translate(:back, :default => 'Back', :scope => [:railties, :scaffold]), <%= plural_name %>_path %>
@@ -0,0 +1,9 @@
1
+ Description:
2
+ Generates a model/attributes translation file for Rails i18n feature.
3
+
4
+ Example:
5
+ ./script/generate i18n locale_name (ja-JP, de-AT, etc.)
6
+
7
+ This will create:
8
+ lib/locale/models_ja-JP.yml
9
+
@@ -0,0 +1,121 @@
1
+ require 'rails_generator'
2
+ require 'rails_generator/commands'
3
+ require File.join(File.dirname(__FILE__), 'lib/translator')
4
+ require File.join(File.dirname(__FILE__), 'lib/recording_backend')
5
+ require File.join(File.dirname(__FILE__), 'lib/erb_executer')
6
+ require File.join(File.dirname(__FILE__), '../i18n/lib/yaml')
7
+ include I18nTranslationGeneratorModule
8
+
9
+ module I18nGenerator::Generator
10
+ module Commands #:nodoc:
11
+ module Create
12
+ def translation_yaml
13
+ I18n.locale = locale_name
14
+ models = model_filenames.map do |model_name|
15
+ model = begin
16
+ m = begin
17
+ model_name.camelize.constantize
18
+ rescue LoadError
19
+ end
20
+ next if m.nil? || !m.table_exists? || !m.respond_to?(:content_columns)
21
+ m.class_eval %Q[def self.english_name; "#{model_name}"; end]
22
+ m
23
+ rescue
24
+ next
25
+ end
26
+ end.compact
27
+ translation_keys = []
28
+ translation_keys += models.map {|m| "activerecord.models.#{m.english_name}"}
29
+ models.each do |model|
30
+ cols = model.content_columns + model.reflect_on_all_associations
31
+ cols.delete_if {|c| %w[created_at updated_at].include? c.name} unless self.include_timestamps
32
+ translation_keys += cols.map {|c| "activerecord.attributes.#{model.english_name}.#{c.name}"}
33
+ end
34
+ logger.debug "#{models.size} models found."
35
+
36
+ # pick all translated keywords from view files
37
+ original_backend = I18n.backend.dup
38
+ I18n.backend = RecordingBackend.new
39
+
40
+ Dir["#{RAILS_ROOT}/app/views/**/*.erb"].each do |f|
41
+ ErbExecuter.new.exec_erb f
42
+ end
43
+ logger.debug "#{I18n.backend.keys.size} translation keys found in views."
44
+ (translation_keys += I18n.backend.keys).uniq!
45
+ I18n.backend = original_backend
46
+
47
+ if translation_keys.blank?
48
+ logger.info "No translation keys found. Skipped generating translation_#{locale_name}.yml file."
49
+ else
50
+ # translate all keys and generate the YAML file
51
+ now = Time.now
52
+ translations = translate_all(translation_keys)
53
+ logger.debug "took #{Time.now - now} secs to translate."
54
+
55
+ yaml = generate_yaml(locale_name, translations).to_s(true)
56
+ template 'i18n:translation.yml', "config/locales/translation_#{locale_name}.yml", :assigns => {:locale_name => locale_name, :translations => yaml}
57
+ end
58
+ end
59
+
60
+ private
61
+ def model_filenames
62
+ Dir.chdir("#{RAILS_ROOT}/app/models/") do
63
+ Dir["**/*.rb"].map {|m| m.sub(/\.rb$/, '')}
64
+ end
65
+ end
66
+
67
+ # mixin translations into existing yaml file
68
+ def generate_yaml(locale_name, translations)
69
+ yaml = YamlDocument.new("config/locales/translation_#{locale_name}.yml", locale_name)
70
+ each_value [], translations do |parents, value|
71
+ node = parents.inject(yaml[locale_name]) {|node, parent| node[parent]}
72
+ node.value = value
73
+ end
74
+ yaml
75
+ end
76
+
77
+ # receives an array of keys and returns :key => :translation hash
78
+ def translate_all(keys)
79
+ returning ActiveSupport::OrderedHash.new do |oh|
80
+ # fix the order first(for multi thread translating)
81
+ keys.each do |key|
82
+ if key.to_s.include? '.'
83
+ key_prefix, key_suffix = key.to_s.split('.')[0...-1], key.to_s.split('.')[-1]
84
+ key_prefix.inject(oh) {|h, k| h[k] ||= ActiveSupport::OrderedHash.new}[key_suffix] = nil
85
+ else
86
+ oh[key] = nil
87
+ end
88
+ end
89
+ threads = []
90
+ keys.each do |key|
91
+ threads << Thread.new do
92
+ logger.debug "translating #{key} ..."
93
+ Thread.pass
94
+ if key.to_s.include? '.'
95
+ key_prefix, key_suffix = key.to_s.split('.')[0...-1], key.to_s.split('.')[-1]
96
+ existing_translation = I18n.t(key, :default => key_suffix, :locale => locale_name)
97
+ key_prefix.inject(oh) {|h, k| h[k]}[key_suffix] = existing_translation != key_suffix ? existing_translation : translator.translate(key_suffix)
98
+ else
99
+ existing_translation = I18n.t(key, :default => key, :locale => locale_name)
100
+ oh[key] = existing_translation != key ? existing_translation : translator.translate(key)
101
+ end
102
+ end
103
+ end
104
+ threads.each {|t| t.join}
105
+ end
106
+ end
107
+
108
+ # iterate through all values
109
+ def each_value(parents, src, &block)
110
+ src.each do |k, v|
111
+ if v.is_a?(ActiveSupport::OrderedHash)
112
+ each_value parents + [k], v, &block
113
+ else
114
+ yield parents + [k], v
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+
@@ -0,0 +1,9 @@
1
+ require File.join(File.dirname(__FILE__), '../i18n/i18n_generator')
2
+
3
+ class I18nTranslationGenerator < I18nGenerator
4
+ def initialize(runtime_args, runtime_options = {})
5
+ super
6
+ options[:generate_translation_only] = true
7
+ end
8
+ end
9
+
@@ -0,0 +1,31 @@
1
+ require "#{File.dirname(__FILE__)}/through_ryoku"
2
+
3
+ module I18nTranslationGeneratorModule
4
+ class ErbExecuter
5
+ def exec_erb(filename)
6
+ begin
7
+ # ERB.new(File.read(f)).result
8
+ (m = Module.new).module_eval <<-EOS
9
+ class Executer
10
+ extend ERB::DefMethod
11
+ include ActionView::Helpers::TranslationHelper
12
+ include I18nTranslationGeneratorModule::ThroughRyoku
13
+
14
+ fname = '#{filename}'
15
+ erb = nil
16
+ File.open(fname) {|f| erb = ERB.new(f.read, nil, '-') }
17
+ erb.def_method(self, 'execute', fname)
18
+ end
19
+ EOS
20
+ nil.class_eval {def method_missing(method, *args, &block); nil; end}
21
+ m.const_get('Executer').new.execute { }
22
+ rescue => e
23
+ p e
24
+ # do nothing
25
+ ensure
26
+ nil.class_eval {undef :method_missing} if nil.respond_to? :method_missing
27
+ end
28
+ end
29
+ end
30
+ end
31
+
@@ -0,0 +1,16 @@
1
+ module I18nTranslationGeneratorModule
2
+ class RecordingBackend
3
+ attr_reader :keys
4
+
5
+ def initialize
6
+ @keys = []
7
+ end
8
+
9
+ def translate(locale, key, options = {})
10
+ # @keys << key.to_sym
11
+ @keys << (Array(options[:scope]) + [key]).flatten.join('.')
12
+ end
13
+ alias :t :translate
14
+ end
15
+ end
16
+
@@ -0,0 +1,8 @@
1
+ module I18nTranslationGeneratorModule
2
+ module ThroughRyoku
3
+ def method_missing(method, *args, &block)
4
+ nil
5
+ end
6
+ end
7
+ end
8
+
@@ -0,0 +1,28 @@
1
+ require 'open-uri'
2
+ require 'json' if RUBY_VERSION >= '1.9'
3
+
4
+ module I18nTranslationGeneratorModule
5
+ class Translator
6
+ def initialize(lang)
7
+ @lang, @cache = lang, {}
8
+ end
9
+
10
+ def translate(word)
11
+ return @cache[word] if @cache[word]
12
+ begin
13
+ w = CGI.escape ActiveSupport::Inflector.humanize(word)
14
+ json = OpenURI.open_uri("http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=#{w}&langpair=en%7C#{@lang}").read
15
+ result = if RUBY_VERSION >= '1.9'
16
+ ::JSON.parse json
17
+ else
18
+ ActiveSupport::JSON.decode(json)
19
+ end
20
+ result['responseStatus'] == 200 ? (@cache[word] = result['responseData']['translatedText']) : word
21
+ rescue => e
22
+ puts %Q[failed to translate "#{word}" into "#{@lang}" language.]
23
+ word
24
+ end
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,87 @@
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{i18n_generators}
8
+ s.version = "0.8.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Akira Matsuda"]
12
+ s.date = %q{2010-08-26}
13
+ s.description = %q{A Rails generator plugin & gem that generates Rails 2.2 and 2.3 I18n locale files for almost every known locale.}
14
+ s.email = %q{ronnie@dio.jp}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "History.txt",
21
+ "MIT-LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "generators/i18n/USAGE",
26
+ "generators/i18n/i18n_generator.rb",
27
+ "generators/i18n/lib/yaml.rb",
28
+ "generators/i18n/templates/base.yml",
29
+ "generators/i18n/templates/i18n_config.rb",
30
+ "generators/i18n/templates/translation.yml",
31
+ "generators/i18n_locale/USAGE",
32
+ "generators/i18n_locale/i18n_locale_command.rb",
33
+ "generators/i18n_locale/i18n_locale_generator.rb",
34
+ "generators/i18n_locale/lib/cldr.rb",
35
+ "generators/i18n_scaffold/i18n_scaffold_generator.rb",
36
+ "generators/i18n_scaffold/templates/controller.rb",
37
+ "generators/i18n_scaffold/templates/functional_test.rb",
38
+ "generators/i18n_scaffold/templates/helper.rb",
39
+ "generators/i18n_scaffold/templates/helper_test.rb",
40
+ "generators/i18n_scaffold/templates/layout.html.erb",
41
+ "generators/i18n_scaffold/templates/style.css",
42
+ "generators/i18n_scaffold/templates/view_edit.html.erb",
43
+ "generators/i18n_scaffold/templates/view_index.html.erb",
44
+ "generators/i18n_scaffold/templates/view_new.html.erb",
45
+ "generators/i18n_scaffold/templates/view_show.html.erb",
46
+ "generators/i18n_translation/USAGE",
47
+ "generators/i18n_translation/i18n_translation_command.rb",
48
+ "generators/i18n_translation/i18n_translation_generator.rb",
49
+ "generators/i18n_translation/lib/erb_executer.rb",
50
+ "generators/i18n_translation/lib/recording_backend.rb",
51
+ "generators/i18n_translation/lib/through_ryoku.rb",
52
+ "generators/i18n_translation/lib/translator.rb",
53
+ "i18n_generators.gemspec",
54
+ "spec/cldr_spec.rb",
55
+ "spec/data/cldr/ja.html",
56
+ "spec/data/yml/active_record/en-US.yml",
57
+ "spec/i18n_locale_command_spec.rb",
58
+ "spec/i18n_translation_command_spec.rb",
59
+ "spec/spec_helper.rb",
60
+ "spec/translator_spec.rb",
61
+ "spec/yaml_spec.rb"
62
+ ]
63
+ s.homepage = %q{http://github.com/amatsuda/i18n_generators/}
64
+ s.rdoc_options = ["--charset=UTF-8"]
65
+ s.require_paths = ["lib"]
66
+ s.rubygems_version = %q{1.3.7}
67
+ s.summary = %q{Generates I18n locale files for Rails 2.2 and 2.3}
68
+ s.test_files = [
69
+ "spec/cldr_spec.rb",
70
+ "spec/i18n_locale_command_spec.rb",
71
+ "spec/i18n_translation_command_spec.rb",
72
+ "spec/spec_helper.rb",
73
+ "spec/translator_spec.rb",
74
+ "spec/yaml_spec.rb"
75
+ ]
76
+
77
+ if s.respond_to? :specification_version then
78
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
79
+ s.specification_version = 3
80
+
81
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
82
+ else
83
+ end
84
+ else
85
+ end
86
+ end
87
+