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
File without changes
@@ -0,0 +1,5 @@
1
+ I18n.load_path += Dir.glob("#{RAILS_ROOT}/lib/locale/*.yml")
2
+
3
+ I18n.default_locale = '<%= locale_name %>'
4
+ I18n.locale = '<%= locale_name %>'
5
+
@@ -0,0 +1 @@
1
+ <%= translations %>
@@ -0,0 +1,12 @@
1
+ Description:
2
+ Generates a config file and locale files for Rails i18n feature.
3
+
4
+ Example:
5
+ ./script/generate i18n locale_name (ja-JP, de-AT, etc.)
6
+
7
+ This will create:
8
+ config/initializers/i18n_config.rb
9
+ lib/locale/action_view_ja-JP.yml
10
+ lib/locale/active_record_ja-JP.yml
11
+ lib/locale/active_support_ja-JP.yml
12
+
@@ -0,0 +1,135 @@
1
+ require 'rubygems'
2
+ require 'rails_generator'
3
+ require 'rails_generator/commands'
4
+ gem 'gettext', '<2'
5
+ require 'gettext'
6
+ require File.join(File.dirname(__FILE__), '../i18n/lib/yaml')
7
+ require File.join(File.dirname(__FILE__), 'lib/cldr')
8
+ include I18nLocaleGeneratorModule
9
+
10
+ module I18nGenerator::Generator
11
+ module Commands #:nodoc:
12
+ module Create
13
+ def generate_configuration
14
+ return if I18n.default_locale == locale_name
15
+ if Rails.configuration.respond_to? :i18n # >= 2.2.2
16
+ # edit environment.rb file
17
+ environment = add_locale_config File.read(File.join(Rails.root, 'config/environment.rb'))
18
+ File.open File.join(Rails.root, 'config/environment.rb'), 'w' do |f|
19
+ f.puts environment
20
+ end
21
+ puts " update config/environment.rb"
22
+ else
23
+ template 'i18n:i18n_config.rb', 'config/initializers/i18n_config.rb', :assigns => {:locale_name => locale_name}
24
+ end
25
+ end
26
+
27
+ def fetch_from_rails_i18n_repository
28
+ file('i18n:base.yml', "config/locales/#{locale_name}.yml") do |f|
29
+ OpenURI.open_uri("http://github.com/svenfuchs/rails-i18n/raw/master/rails/locale/#{locale_name}.yml").read
30
+ end
31
+ end
32
+
33
+ def active_support_yaml
34
+ open_yaml('active_support') do |yaml|
35
+ yaml[locale_name].descendant_nodes do |node|
36
+ v = cldr.lookup(node.path)
37
+ node.value = v if !v.nil? && !(v.is_a?(Array) && v.any? {|e| e.nil?})
38
+ end
39
+ end
40
+ end
41
+
42
+ def active_record_yaml
43
+ open_yaml('active_record') do |yaml|
44
+ yaml[locale_name]['activerecord']['errors']['messages'].children.each do |node|
45
+ unless node.value.nil?
46
+ node.value = transfer_format('%{fn} ' + node.value.gsub('{{count}}', '%d')) do |v|
47
+ GetText._(v)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def action_view_yaml
55
+ open_yaml('action_view') do |yaml|
56
+ yaml[locale_name]['datetime']['distance_in_words'].children.each do |node|
57
+ if !node.value.nil?
58
+ node.value = GetText._(node.value)
59
+ elsif ((children = node.children).size == 2) && (children.map(&:key) == %w[one other])
60
+ children['one'].value, children['other'].value = translate_one_and_other(children.map(&:value))
61
+ end
62
+ end
63
+ yaml[locale_name]['activerecord']['errors']['template'].children.each do |node|
64
+ if !node.value.nil?
65
+ node.value = if node.value == 'There were problems with the following fields:'
66
+ GetText.n_('There was a problem with the following field:', node.value, 2)
67
+ else
68
+ GetText._(node.value)
69
+ end
70
+ elsif ((children = node.children).size == 2) && (children.map(&:key) == %w[one other])
71
+ children['one'].value, children['other'].value = if children['one'].value == '1 error prohibited this {{model}} from being saved'
72
+ translate_one_and_other(['%{num} error prohibited this {{model}} from being saved', children['other']])
73
+ else
74
+ translate_one_and_other(children.map(&:value))
75
+ end
76
+ end
77
+ end
78
+ yaml[locale_name]['number'].descendant_nodes do |node|
79
+ v = cldr.lookup(node.path)
80
+ node.value = v if !v.nil? && !(v.is_a?(Array) && v.any? {|e| e.nil?})
81
+ end
82
+ end
83
+ end
84
+
85
+ private
86
+ def add_locale_config(environment_contents)
87
+ (arr = environment_contents.split("\n")).each_with_index do |l, i|
88
+ if l =~ /^\s*config\.i18n\.default_locale = /
89
+ arr[i] = " config.i18n.default_locale = '#{locale_name}'"
90
+ return arr.join("\n")
91
+ end
92
+ end
93
+ arr.each_with_index do |l, i|
94
+ if l =~ /^\s*#?\s*config\.i18n\.default_locale = /
95
+ arr[i] = " config.i18n.default_locale = '#{locale_name}'"
96
+ return arr.join("\n")
97
+ end
98
+ end
99
+ arr.each_with_index do |l, i|
100
+ if l =~ /Rails::Initializer\.run do \|config\|/
101
+ arr[i] = "Rails::Initializer.run do |config|\n config.i18n.default_locale = '#{locale_name}'"
102
+ return arr.join("\n")
103
+ end
104
+ end
105
+ end_row = RUBY_VERSION >= '1.8.7' ? arr.rindex {|l| l =~ /^\s*end\s*/} : arr.size - 1
106
+ ((arr[0...end_row] << " config.i18n.default_locale = '#{locale_name}'") + arr[end_row..-1]).join("\n")
107
+ end
108
+
109
+ def open_yaml(filename_base)
110
+ original_yml = I18n.load_path.detect {|lp| lp =~ /\/lib\/#{filename_base}\/locale\/(en|en-US)\.yml$/}
111
+ doc = YamlDocument.new(original_yml, locale_name)
112
+ yield doc
113
+ file('i18n:base.yml', "config/locales/#{filename_base}_#{locale_name}.yml") do |f|
114
+ doc.to_s
115
+ end
116
+ end
117
+
118
+ def transfer_format(args)
119
+ vals = if args.is_a?(Array)
120
+ args.map {|v| v.gsub('{{count}}', '%d').gsub('{{model}}', '%{record}')}
121
+ else
122
+ args.gsub('{{count}}', '%d').gsub('{{model}}', '%{record}')
123
+ end
124
+ result = yield vals
125
+ result.gsub(/^%\{fn\}/, '').gsub('%d', '{{count}}').gsub('%{record}', '{{model}}').gsub('%{num}', '{{count}}').strip
126
+ end
127
+
128
+ def translate_one_and_other(values)
129
+ values = values.map {|v| v.is_a?(Node) ? v.value : v}
130
+ [transfer_format(values) {|v| GetText.n_(v.first, v.second, 1)}, transfer_format(values) {|v| GetText.n_(v.first, v.second, 2)}]
131
+ end
132
+ end
133
+ end
134
+ end
135
+
@@ -0,0 +1,9 @@
1
+ require File.join(File.dirname(__FILE__), '../i18n/i18n_generator')
2
+
3
+ class I18nLocaleGenerator < I18nGenerator
4
+ def initialize(runtime_args, runtime_options = {})
5
+ super
6
+ options[:generate_locale_only] = true
7
+ end
8
+ end
9
+
@@ -0,0 +1,139 @@
1
+ # encoding: utf-8
2
+ $KCODE = 'U'
3
+
4
+ require 'open-uri'
5
+
6
+ module I18nLocaleGeneratorModule
7
+ class CldrDocument
8
+ extend ActiveSupport::Memoizable
9
+
10
+ def initialize(locale_name)
11
+ @locale_name = locale_name
12
+ end
13
+
14
+ def lookup(path)
15
+ case path.sub(/^\/#{@locale_name}\//, '')
16
+ when 'date/formats/default'
17
+ convert_date_pattern search('calendar-gregorian', 'pattern', 'date-medium')
18
+ when 'date/formats/short'
19
+ convert_date_pattern search('calendar-gregorian', 'pattern', 'date-short')
20
+ when 'date/formats/long'
21
+ convert_date_pattern search('calendar-gregorian', 'pattern', 'date-full')
22
+ when 'date/day_names'
23
+ [search('calendar-gregorian', 'day', 'sunday:format-wide'),
24
+ search('calendar-gregorian', 'day', 'monday:format-wide'),
25
+ search('calendar-gregorian', 'day', 'tuesday:format-wide'),
26
+ search('calendar-gregorian', 'day', 'wednesday:format-wide'),
27
+ search('calendar-gregorian', 'day', 'thursday:format-wide'),
28
+ search('calendar-gregorian', 'day', 'friday:format-wide'),
29
+ search('calendar-gregorian', 'day', 'saturday:format-wide')]
30
+ when 'date/abbr_day_names'
31
+ [search('calendar-gregorian', 'day', 'sunday:format-abbreviated'),
32
+ search('calendar-gregorian', 'day', 'monday:format-abbreviated'),
33
+ search('calendar-gregorian', 'day', 'tuesday:format-abbreviated'),
34
+ search('calendar-gregorian', 'day', 'wednesday:format-abbreviated'),
35
+ search('calendar-gregorian', 'day', 'thursday:format-abbreviated'),
36
+ search('calendar-gregorian', 'day', 'friday:format-abbreviated'),
37
+ search('calendar-gregorian', 'day', 'saturday:format-abbreviated')]
38
+ when 'date/month_names'
39
+ ['~',
40
+ search('calendar-gregorian', 'month', '[01]-format-wide'),
41
+ search('calendar-gregorian', 'month', '[02]-format-wide'),
42
+ search('calendar-gregorian', 'month', '[03]-format-wide'),
43
+ search('calendar-gregorian', 'month', '[04]-format-wide'),
44
+ search('calendar-gregorian', 'month', '[05]-format-wide'),
45
+ search('calendar-gregorian', 'month', '[06]-format-wide'),
46
+ search('calendar-gregorian', 'month', '[07]-format-wide'),
47
+ search('calendar-gregorian', 'month', '[08]-format-wide'),
48
+ search('calendar-gregorian', 'month', '[09]-format-wide'),
49
+ search('calendar-gregorian', 'month', '[10]-format-wide'),
50
+ search('calendar-gregorian', 'month', '[11]-format-wide'),
51
+ search('calendar-gregorian', 'month', '[12]-format-wide')]
52
+ when 'date/abbr_month_names'
53
+ ['~',
54
+ search('calendar-gregorian', 'month', '[01]-format-abbreviated'),
55
+ search('calendar-gregorian', 'month', '[02]-format-abbreviated'),
56
+ search('calendar-gregorian', 'month', '[03]-format-abbreviated'),
57
+ search('calendar-gregorian', 'month', '[04]-format-abbreviated'),
58
+ search('calendar-gregorian', 'month', '[05]-format-abbreviated'),
59
+ search('calendar-gregorian', 'month', '[06]-format-abbreviated'),
60
+ search('calendar-gregorian', 'month', '[07]-format-abbreviated'),
61
+ search('calendar-gregorian', 'month', '[08]-format-abbreviated'),
62
+ search('calendar-gregorian', 'month', '[09]-format-abbreviated'),
63
+ search('calendar-gregorian', 'month', '[10]-format-abbreviated'),
64
+ search('calendar-gregorian', 'month', '[11]-format-abbreviated'),
65
+ search('calendar-gregorian', 'month', '[12]-format-abbreviated')]
66
+ # when 'date/order'
67
+ when 'time/formats/default'
68
+ format = search('calendar-gregorian', 'pattern', 'date+time')
69
+ date = convert_date_pattern search('calendar-gregorian', 'pattern', 'date-medium')
70
+ time = convert_date_pattern search('calendar-gregorian', 'pattern', 'time-medium')
71
+ (format.nil? || date.nil? || time.nil?) ? nil : format.sub('{0}', time).sub('{1}', date)
72
+ when 'time/formats/short'
73
+ format = search('calendar-gregorian', 'pattern', 'date+time')
74
+ date = convert_date_pattern search('calendar-gregorian', 'pattern', 'date-short')
75
+ time = convert_date_pattern search('calendar-gregorian', 'pattern', 'time-short')
76
+ (format.nil? || date.nil? || time.nil?) ? nil : format.sub('{0}', time).sub('{1}', date)
77
+ when 'time/formats/long'
78
+ format = search('calendar-gregorian', 'pattern', 'date+time')
79
+ date = convert_date_pattern search('calendar-gregorian', 'pattern', 'date-full')
80
+ time = convert_date_pattern search('calendar-gregorian', 'pattern', 'time-full')
81
+ (format.nil? || date.nil? || time.nil?) ? nil : format.sub('{0}', time).sub('{1}', date)
82
+ when 'time/am'
83
+ search('calendar-gregorian', 'day-period', 'am')
84
+ when 'time/pm'
85
+ search('calendar-gregorian', 'day-period', 'pm')
86
+ # action_view
87
+ when 'number/format/separator'
88
+ search('number', 'symbol', 'decimal')
89
+ when 'number/format/separator'
90
+ search('number', 'symbol', 'group')
91
+ when 'number/currency/format/format'
92
+ format = search('number', 'currency', 'name-pattern/​other')
93
+ format.nil? ? nil : format.tr(' ', '').sub('{0}', '%u').sub('{1}', '%n')
94
+ else
95
+ nil
96
+ end
97
+ end
98
+
99
+ private
100
+ def summaries
101
+ returning [load_cldr_data(@locale_name.tr('-', '_'))] do |s|
102
+ if @locale_name =~ /^[a-zA-Z]{2}[-_][a-zA-Z]{2}$/
103
+ s << load_cldr_data(@locale_name.to(1))
104
+ end
105
+ end
106
+ end
107
+ memoize :summaries
108
+
109
+ def load_cldr_data(locale_name)
110
+ cldr = begin
111
+ OpenURI.open_uri("http://www.unicode.org/cldr/data/charts/summary/#{locale_name}.html").read
112
+ rescue
113
+ puts "WARNING: Couldn't find locale data for #{locale_name} on the web."
114
+ ''
115
+ end
116
+ lines = cldr.split("\n").grep(/^<tr>/)
117
+ lines.delete_if {|r| r =~ /^<tr><td>\d*<\/td><td class='[gn]'>names<\/td>/}
118
+ 'Ruby 1.9'.respond_to?(:force_encoding) ? lines.map {|l| l.force_encoding 'UTF-8'} : lines
119
+ end
120
+
121
+ def search(n1, n2, g)
122
+ pattern = Regexp.new /<tr><td>\d*<\/td><td class='[ng]'>#{Regexp.quote(n1)}<\/td><td class='[ng]'>#{Regexp.quote(n2)}<\/td><td class='[ng]'>#{Regexp.quote(g)}<\/td>/
123
+ extract_pattern = /<td class='v'>(?:<span.*?>)?(.*?)(?:<\/span>)?<\/td><td>/
124
+ summaries.each do |summary|
125
+ _, value = *extract_pattern.match(summary.grep(pattern).first)
126
+ return value unless value.nil?
127
+ end
128
+ nil
129
+ end
130
+
131
+ def convert_date_pattern(val)
132
+ return val if val.nil?
133
+ val = val.sub('MMMM', '%B').sub('MMM', '%b')
134
+ val = val.sub('yyyy', '%Y').sub('yy', '%y').sub('MM', '%m').sub('M', '%m').sub(/dd|d/, '%d')
135
+ val.sub('EEEEE', '%a').sub('EEEE', '%A').sub('H', '%H').sub('mm', '%M').sub('ss', '%S').sub('v', '%Z')
136
+ end
137
+ end
138
+ end
139
+
@@ -0,0 +1,3 @@
1
+ class I18nScaffoldGenerator < ScaffoldGenerator
2
+ end
3
+
@@ -0,0 +1,85 @@
1
+ class <%= controller_class_name %>Controller < ApplicationController
2
+ # GET /<%= table_name %>
3
+ # GET /<%= table_name %>.xml
4
+ def index
5
+ @<%= table_name %> = <%= class_name %>.find(:all)
6
+
7
+ respond_to do |format|
8
+ format.html # index.html.erb
9
+ format.xml { render :xml => @<%= table_name %> }
10
+ end
11
+ end
12
+
13
+ # GET /<%= table_name %>/1
14
+ # GET /<%= table_name %>/1.xml
15
+ def show
16
+ @<%= file_name %> = <%= class_name %>.find(params[:id])
17
+
18
+ respond_to do |format|
19
+ format.html # show.html.erb
20
+ format.xml { render :xml => @<%= file_name %> }
21
+ end
22
+ end
23
+
24
+ # GET /<%= table_name %>/new
25
+ # GET /<%= table_name %>/new.xml
26
+ def new
27
+ @<%= file_name %> = <%= class_name %>.new
28
+
29
+ respond_to do |format|
30
+ format.html # new.html.erb
31
+ format.xml { render :xml => @<%= file_name %> }
32
+ end
33
+ end
34
+
35
+ # GET /<%= table_name %>/1/edit
36
+ def edit
37
+ @<%= file_name %> = <%= class_name %>.find(params[:id])
38
+ end
39
+
40
+ # POST /<%= table_name %>
41
+ # POST /<%= table_name %>.xml
42
+ def create
43
+ @<%= file_name %> = <%= class_name %>.new(params[:<%= file_name %>])
44
+
45
+ respond_to do |format|
46
+ if @<%= file_name %>.save
47
+ flash[:notice] = I18n.t(:created_success, :default => '{{model}} was successfully created.', :model => <%= class_name %>.human_name, :scope => [:railties, :scaffold])
48
+ format.html { redirect_to(@<%= file_name %>) }
49
+ format.xml { render :xml => @<%= file_name %>, :status => :created, :location => @<%= file_name %> }
50
+ else
51
+ format.html { render :action => "new" }
52
+ format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity }
53
+ end
54
+ end
55
+ end
56
+
57
+ # PUT /<%= table_name %>/1
58
+ # PUT /<%= table_name %>/1.xml
59
+ def update
60
+ @<%= file_name %> = <%= class_name %>.find(params[:id])
61
+
62
+ respond_to do |format|
63
+ if @<%= file_name %>.update_attributes(params[:<%= file_name %>])
64
+ flash[:notice] = I18n.t(:updated_success, :default => '{{model}} was successfully updated.', :model => <%= class_name %>.human_name, :scope => [:railties, :scaffold])
65
+ format.html { redirect_to(@<%= file_name %>) }
66
+ format.xml { head :ok }
67
+ else
68
+ format.html { render :action => "edit" }
69
+ format.xml { render :xml => @<%= file_name %>.errors, :status => :unprocessable_entity }
70
+ end
71
+ end
72
+ end
73
+
74
+ # DELETE /<%= table_name %>/1
75
+ # DELETE /<%= table_name %>/1.xml
76
+ def destroy
77
+ @<%= file_name %> = <%= class_name %>.find(params[:id])
78
+ @<%= file_name %>.destroy
79
+
80
+ respond_to do |format|
81
+ format.html { redirect_to(<%= table_name %>_url) }
82
+ format.xml { head :ok }
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,45 @@
1
+ require 'test_helper'
2
+
3
+ class <%= controller_class_name %>ControllerTest < ActionController::TestCase
4
+ test "should get index" do
5
+ get :index
6
+ assert_response :success
7
+ assert_not_nil assigns(:<%= table_name %>)
8
+ end
9
+
10
+ test "should get new" do
11
+ get :new
12
+ assert_response :success
13
+ end
14
+
15
+ test "should create <%= file_name %>" do
16
+ assert_difference('<%= class_name %>.count') do
17
+ post :create, :<%= file_name %> => { }
18
+ end
19
+
20
+ assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>))
21
+ end
22
+
23
+ test "should show <%= file_name %>" do
24
+ get :show, :id => <%= table_name %>(:one).id
25
+ assert_response :success
26
+ end
27
+
28
+ test "should get edit" do
29
+ get :edit, :id => <%= table_name %>(:one).id
30
+ assert_response :success
31
+ end
32
+
33
+ test "should update <%= file_name %>" do
34
+ put :update, :id => <%= table_name %>(:one).id, :<%= file_name %> => { }
35
+ assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>))
36
+ end
37
+
38
+ test "should destroy <%= file_name %>" do
39
+ assert_difference('<%= class_name %>.count', -1) do
40
+ delete :destroy, :id => <%= table_name %>(:one).id
41
+ end
42
+
43
+ assert_redirected_to <%= table_name %>_path
44
+ end
45
+ end