i18n_generators 0.8.0

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.
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
+