middleman-more 3.1.0.beta.1 → 3.1.0.beta.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,174 +1,150 @@
1
- require "i18n"
2
- require "i18n/backend/fallbacks"
1
+ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
2
+ option :no_fallbacks, false, "Disable I18n fallbacks"
3
+ option :langs, nil, "List of langs, will autodiscover by default"
4
+ option :lang_map, {}, "Language shortname map"
5
+ option :path, "/:locale/", "URL prefix path"
6
+ option :templates_dir, "localizable", "Location of templates to be localized"
7
+ option :mount_at_root, nil, "Mount a specific language at the root of the site"
8
+ option :data, "locales", "The directory holding your locale configurations"
9
+
10
+ def initialize(app, options_hash={}, &block)
11
+ super
12
+
13
+ # See https://github.com/svenfuchs/i18n/wiki/Fallbacks
14
+ unless options[:no_fallbacks]
15
+ require "i18n/backend/fallbacks"
16
+ ::I18n::Backend::Simple.send(:include, ::I18n::Backend::Fallbacks)
17
+ end
3
18
 
4
- module Middleman
5
- module CoreExtensions
19
+ app.config.define_setting :locales_dir, "locales", 'The directory holding your locale configurations'
20
+ end
6
21
 
7
- # i18n Namespace
8
- module Internationalization
22
+ def after_configuration
23
+ @locales_glob = File.join(app.config[:locals_dir] || options[:data], "**", "*.{rb,yml,yaml}")
9
24
 
10
- # Setup extension
11
- class << self
25
+ # File.fnmatch doesn't support brackets: {rb,yml,yaml}
26
+ regex = @locales_glob.sub(/\./, '\.').sub(File.join("**", "*"), ".*").sub(/\//, '\/').sub("{rb,yml,yaml}", "rb|ya?ml")
27
+ @locales_regex = %r{^#{regex}}
12
28
 
13
- # Once registerd
14
- def registered(app, options={})
15
- app.config.define_setting :locales_dir, "locales", 'The directory holding your locale configurations'
29
+ @maps = {}
16
30
 
17
- # Needed for helpers as well
18
- app.after_configuration do
19
- Localizer.new(self, options)
20
- end
31
+ ::I18n.load_path += Dir[File.join(app.root, @locales_glob)]
32
+ ::I18n.reload!
21
33
 
22
- app.helpers do
23
- def t(*args)
24
- ::I18n.t(*args)
25
- end
26
- end
34
+ @mount_at_root = options[:mount_at_root].nil? ? langs.first : options[:mount_at_root]
27
35
 
28
- # See https://github.com/svenfuchs/i18n/wiki/Fallbacks
29
- unless options[:no_fallbacks]
30
- ::I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
31
- end
32
- end
33
- alias :included :registered
34
- end
36
+ ::I18n.default_locale = @mount_at_root
37
+ # Reset fallbacks to fall back to our new default
38
+ if ::I18n.respond_to? :fallbacks
39
+ ::I18n.fallbacks = ::I18n::Locale::Fallbacks.new
40
+ end
35
41
 
36
- # Central class for managing i18n extension
37
- class Localizer
38
- attr_reader :app
39
- delegate :logger, :to => :app
40
-
41
- def initialize(app, options={})
42
- @app = app
43
- @locales_glob = File.join(app.locales_dir, "**", "*.{rb,yml,yaml}")
44
-
45
- # File.fnmatch doesn't support brackets: {rb,yml,yaml}
46
- regex = @locales_glob.sub(/\./, '\.').sub(File.join("**", "*"), ".*").sub(/\//, '\/').sub("{rb,yml,yaml}", "rb|ya?ml")
47
- @locales_regex = %r{^#{regex}}
48
-
49
- @maps = {}
50
- @options = options
51
-
52
- ::I18n.load_path += Dir[File.join(app.root, @locales_glob)]
53
- ::I18n.reload!
54
-
55
- @lang_map = @options[:lang_map] || {}
56
- @path = @options[:path] || "/:locale/"
57
- @templates_dir = @options[:templates_dir] || "localizable"
58
- @mount_at_root = @options.has_key?(:mount_at_root) ? @options[:mount_at_root] : langs.first
59
-
60
- ::I18n.default_locale = @mount_at_root
61
- # Reset fallbacks to fall back to our new default
62
- if ::I18n.respond_to? :fallbacks
63
- ::I18n.fallbacks = ::I18n::Locale::Fallbacks.new
64
- end
65
-
66
- if !@app.build?
67
- logger.info "== Locales: #{langs.join(", ")} (Default #{@mount_at_root})"
68
- end
69
-
70
- # Don't output localizable files
71
- @app.ignore File.join(@templates_dir, "**")
72
-
73
- @app.sitemap.provides_metadata_for_path do |url|
74
- if d = get_localization_data(url)
75
- lang, page_id = d
76
- else
77
- # Default to the @mount_at_root lang
78
- page_id = nil
79
- lang = @mount_at_root
80
- end
81
-
82
- instance_vars = Proc.new do
83
- @lang = lang
84
- @page_id = page_id
85
- end
86
-
87
- locals = { :lang => lang,
88
- :page_id => page_id }
89
- { :blocks => [instance_vars],
90
- :locals => locals,
91
- :options => { :lang => lang } }
92
- end
93
-
94
- @app.sitemap.register_resource_list_manipulator(
95
- :i18n,
96
- self
97
- )
98
-
99
- @app.files.changed(&method(:on_file_changed))
100
- @app.files.deleted(&method(:on_file_changed))
101
- end
42
+ if !app.build?
43
+ logger.info "== Locales: #{langs.join(", ")} (Default #{@mount_at_root})"
44
+ end
102
45
 
103
- def on_file_changed(file)
104
- if @locales_regex =~ file
105
- ::I18n.reload!
106
- end
107
- end
46
+ # Don't output localizable files
47
+ app.ignore File.join(options[:templates_dir], "**")
108
48
 
109
- def langs
110
- if @options[:langs]
111
- Array(@options[:langs]).map(&:to_sym)
112
- else
113
- Dir[File.join(@app.root, @locales_glob)].map { |file|
114
- File.basename(file).sub(/\.ya?ml$/, "").sub(/\.rb$/, "")
115
- }.sort.map(&:to_sym)
116
- end
117
- end
49
+ app.sitemap.provides_metadata_for_path do |url|
50
+ if d = get_localization_data(url)
51
+ lang, page_id = d
52
+ else
53
+ # Default to the @mount_at_root lang
54
+ page_id = nil
55
+ lang = @mount_at_root
56
+ end
118
57
 
119
- def get_localization_data(path)
120
- @_localization_data ||= {}
121
- @_localization_data[path]
122
- end
58
+ instance_vars = Proc.new do
59
+ @lang = lang
60
+ @page_id = page_id
61
+ end
62
+
63
+ locals = { :lang => lang,
64
+ :page_id => page_id }
65
+ { :blocks => [instance_vars],
66
+ :locals => locals,
67
+ :options => { :lang => lang } }
68
+ end
123
69
 
124
- # Update the main sitemap resource list
125
- # @return [void]
126
- def manipulate_resource_list(resources)
127
- @_localization_data = {}
70
+ app.files.changed(&method(:on_file_changed))
71
+ app.files.deleted(&method(:on_file_changed))
72
+ end
128
73
 
129
- new_resources = []
74
+ helpers do
75
+ def t(*args)
76
+ ::I18n.t(*args)
77
+ end
78
+ end
130
79
 
131
- resources.each do |resource|
132
- next unless File.fnmatch(File.join(@templates_dir, "**"), resource.path)
80
+ delegate :logger, :to => :app
133
81
 
134
- page_id = File.basename(resource.path, File.extname(resource.path))
82
+ def on_file_changed(file)
83
+ if @locales_regex =~ file
84
+ ::I18n.reload!
85
+ end
86
+ end
135
87
 
136
- old_locale = ::I18n.locale
137
- langs.map do |lang|
138
- ::I18n.locale = lang
88
+ def langs
89
+ if options[:langs]
90
+ Array(options[:langs]).map(&:to_sym)
91
+ else
92
+ Dir[File.join(app.root, @locales_glob)].map { |file|
93
+ File.basename(file).sub(/\.ya?ml$/, "").sub(/\.rb$/, "")
94
+ }.sort.map(&:to_sym)
95
+ end
96
+ end
139
97
 
140
- localized_page_id = ::I18n.t("paths.#{page_id}", :default => page_id, :fallback => [])
141
- path = resource.path.sub(@templates_dir, "")
98
+ def get_localization_data(path)
99
+ @_localization_data ||= {}
100
+ @_localization_data[path]
101
+ end
142
102
 
143
- # Build lang path
144
- if @mount_at_root == lang
145
- prefix = "/"
146
- else
147
- replacement = @lang_map.has_key?(lang) ? @lang_map[lang] : lang
148
- prefix = @path.sub(":locale", replacement.to_s)
149
- end
103
+ # Update the main sitemap resource list
104
+ # @return [void]
105
+ def manipulate_resource_list(resources)
106
+ @_localization_data = {}
150
107
 
151
- path = ::Middleman::Util.normalize_path(
152
- File.join(prefix, path.sub(page_id, localized_page_id))
153
- )
108
+ new_resources = []
154
109
 
155
- @_localization_data[path] = [lang, path, localized_page_id]
110
+ resources.each do |resource|
111
+ next unless File.fnmatch(File.join(options[:templates_dir], "**"), resource.path)
156
112
 
157
- p = ::Middleman::Sitemap::Resource.new(
158
- @app.sitemap,
159
- path
160
- )
161
- p.proxy_to(resource.path)
113
+ page_id = File.basename(resource.path, File.extname(resource.path))
162
114
 
163
- new_resources << p
164
- end
165
- ::I18n.locale = old_locale
115
+ old_locale = ::I18n.locale
116
+ langs.map do |lang|
117
+ ::I18n.locale = lang
166
118
 
167
- end
119
+ localized_page_id = ::I18n.t("paths.#{page_id}", :default => page_id, :fallback => [])
120
+ path = resource.path.sub(options[:templates_dir], "")
168
121
 
169
- resources + new_resources
122
+ # Build lang path
123
+ if @mount_at_root == lang
124
+ prefix = "/"
125
+ else
126
+ replacement = options[:lang_map].has_key?(lang) ? options[:lang_map][lang] : lang
127
+ prefix = options[:path].sub(":locale", replacement.to_s)
170
128
  end
129
+
130
+ path = ::Middleman::Util.normalize_path(
131
+ File.join(prefix, path.sub(page_id, localized_page_id))
132
+ )
133
+
134
+ @_localization_data[path] = [lang, path, localized_page_id]
135
+
136
+ p = ::Middleman::Sitemap::Resource.new(
137
+ app.sitemap,
138
+ path
139
+ )
140
+ p.proxy_to(resource.path)
141
+
142
+ new_resources << p
171
143
  end
144
+ ::I18n.locale = old_locale
145
+
172
146
  end
147
+
148
+ resources + new_resources
173
149
  end
174
150
  end
@@ -1,124 +1,104 @@
1
- module Middleman
2
- module Extensions
3
- module AssetHash
4
- class Extension < ::Middleman::Extension
5
- option :exts, %w(.jpg .jpeg .png .gif .js .css .otf .woff .eot .ttf .svg), "List of extensions that get asset hashes appended to them."
6
- option :ignore, [], "Regexes of filenames to skip adding asset hashes to"
7
-
8
- def initialize(app, options_hash={})
9
- super
10
-
11
- require 'digest/sha1'
12
- require 'rack/test'
13
- require 'uri'
14
- end
1
+ class Middleman::Extensions::AssetHash < ::Middleman::Extension
2
+ option :exts, %w(.jpg .jpeg .png .gif .js .css .otf .woff .eot .ttf .svg), "List of extensions that get asset hashes appended to them."
3
+ option :ignore, [], "Regexes of filenames to skip adding asset hashes to"
15
4
 
16
- def after_configuration
17
- # Allow specifying regexes to ignore, plus always ignore apple touch icons
18
- ignore = Array(options.ignore) + [/^apple-touch-icon/]
5
+ def initialize(app, options_hash={}, &block)
6
+ super
19
7
 
20
- app.sitemap.register_resource_list_manipulator(
21
- :asset_hash,
22
- AssetHashManager.new(app, options.exts, ignore)
23
- )
8
+ require 'digest/sha1'
9
+ require 'rack/test'
10
+ require 'uri'
11
+ end
24
12
 
25
- app.use Middleware, :exts => options.exts, :middleman_app => app, :ignore => ignore
26
- end
27
- end
13
+ def after_configuration
14
+ # Allow specifying regexes to ignore, plus always ignore apple touch icons
15
+ @ignore = Array(options.ignore) + [/^apple-touch-icon/]
28
16
 
29
- # Central class for managing asset_hash extension
30
- class AssetHashManager
31
- def initialize(app, exts, ignore)
32
- @app = app
33
- @exts = exts
34
- @ignore = ignore
35
- end
17
+ app.use Middleware, :exts => options.exts, :middleman_app => app, :ignore => @ignore
18
+ end
36
19
 
37
- # Update the main sitemap resource list
38
- # @return [void]
39
- def manipulate_resource_list(resources)
40
- # Process resources in order: binary images and fonts, then SVG, then JS/CSS.
41
- # This is so by the time we get around to the text files (which may reference
42
- # images and fonts) the static assets' hashes are already calculated.
43
- rack_client = ::Rack::Test::Session.new(@app.class.to_rack_app)
44
- resources.sort_by do |a|
45
- if %w(.svg).include? a.ext
46
- 0
47
- elsif %w(.js .css).include? a.ext
48
- 1
49
- else
50
- -1
51
- end
52
- end.each do |resource|
53
- next unless @exts.include? resource.ext
54
- next if @ignore.any? { |ignore| Middleman::Util.path_match(ignore, resource.destination_path) }
20
+ # Update the main sitemap resource list
21
+ # @return [void]
22
+ def manipulate_resource_list(resources)
23
+ # Process resources in order: binary images and fonts, then SVG, then JS/CSS.
24
+ # This is so by the time we get around to the text files (which may reference
25
+ # images and fonts) the static assets' hashes are already calculated.
26
+ rack_client = ::Rack::Test::Session.new(app.class.to_rack_app)
27
+ resources.sort_by do |a|
28
+ if %w(.svg).include? a.ext
29
+ 0
30
+ elsif %w(.js .css).include? a.ext
31
+ 1
32
+ else
33
+ -1
34
+ end
35
+ end.each do |resource|
36
+ next unless options.exts.include? resource.ext
37
+ next if @ignore.any? { |ignore| Middleman::Util.path_match(ignore, resource.destination_path) }
55
38
 
56
- # Render through the Rack interface so middleware and mounted apps get a shot
57
- response = rack_client.get(URI.escape(resource.destination_path), {}, { "bypass_asset_hash" => "true" })
58
- raise "#{resource.path} should be in the sitemap!" unless response.status == 200
39
+ # Render through the Rack interface so middleware and mounted apps get a shot
40
+ response = rack_client.get(URI.escape(resource.destination_path), {}, { "bypass_asset_hash" => "true" })
41
+ raise "#{resource.path} should be in the sitemap!" unless response.status == 200
59
42
 
60
- digest = Digest::SHA1.hexdigest(response.body)[0..7]
43
+ digest = Digest::SHA1.hexdigest(response.body)[0..7]
61
44
 
62
- resource.destination_path = resource.destination_path.sub(/\.(\w+)$/) { |ext| "-#{digest}#{ext}" }
63
- end
64
- end
65
- end
66
-
67
- # The asset hash middleware is responsible for rewriting references to
68
- # assets to include their new, hashed name.
69
- class Middleware
70
- def initialize(app, options={})
71
- @rack_app = app
72
- @exts = options[:exts]
73
- @ignore = options[:ignore]
74
- @exts_regex_text = @exts.map {|e| Regexp.escape(e) }.join('|')
75
- @middleman_app = options[:middleman_app]
76
- end
45
+ resource.destination_path = resource.destination_path.sub(/\.(\w+)$/) { |ext| "-#{digest}#{ext}" }
46
+ end
47
+ end
77
48
 
78
- def call(env)
79
- status, headers, response = @rack_app.call(env)
49
+ # The asset hash middleware is responsible for rewriting references to
50
+ # assets to include their new, hashed name.
51
+ class Middleware
52
+ def initialize(app, options={})
53
+ @rack_app = app
54
+ @exts = options[:exts]
55
+ @ignore = options[:ignore]
56
+ @exts_regex_text = @exts.map {|e| Regexp.escape(e) }.join('|')
57
+ @middleman_app = options[:middleman_app]
58
+ end
80
59
 
81
- # We don't want to use this middleware when rendering files to figure out their hash!
82
- return [status, headers, response] if env["bypass_asset_hash"] == 'true'
60
+ def call(env)
61
+ status, headers, response = @rack_app.call(env)
83
62
 
84
- path = @middleman_app.full_path(env["PATH_INFO"])
85
- dirpath = Pathname.new(File.dirname(path))
63
+ # We don't want to use this middleware when rendering files to figure out their hash!
64
+ return [status, headers, response] if env["bypass_asset_hash"] == 'true'
86
65
 
87
- if path =~ /(^\/$)|(\.(htm|html|php|css|js)$)/
88
- body = ::Middleman::Util.extract_response_text(response)
66
+ path = @middleman_app.full_path(env["PATH_INFO"])
67
+ dirpath = Pathname.new(File.dirname(path))
89
68
 
90
- if body
91
- # TODO: This regex will change some paths in plan HTML (not in a tag) - is that OK?
92
- body.gsub! /([=\'\"\(]\s*)([^\s\'\"\)]+(#{@exts_regex_text}))/ do |match|
93
- opening_character = $1
94
- asset_path = $2
69
+ if path =~ /(^\/$)|(\.(htm|html|php|css|js)$)/
70
+ body = ::Middleman::Util.extract_response_text(response)
95
71
 
96
- relative_path = Pathname.new(asset_path).relative?
72
+ if body
73
+ # TODO: This regex will change some paths in plan HTML (not in a tag) - is that OK?
74
+ body.gsub!(/([=\'\"\(]\s*)([^\s\'\"\)]+(#{@exts_regex_text}))/) do |match|
75
+ opening_character = $1
76
+ asset_path = $2
97
77
 
98
- asset_path = dirpath.join(asset_path).to_s if relative_path
78
+ relative_path = Pathname.new(asset_path).relative?
99
79
 
100
- if @ignore.any? { |r| asset_path.match(r) }
101
- match
102
- elsif asset_page = @middleman_app.sitemap.find_resource_by_path(asset_path)
103
- replacement_path = "/#{asset_page.destination_path}"
104
- replacement_path = Pathname.new(replacement_path).relative_path_from(dirpath).to_s if relative_path
80
+ asset_path = dirpath.join(asset_path).to_s if relative_path
105
81
 
106
- "#{opening_character}#{replacement_path}"
107
- else
108
- match
109
- end
110
- end
82
+ if @ignore.any? { |r| asset_path.match(r) }
83
+ match
84
+ elsif asset_page = @middleman_app.sitemap.find_resource_by_path(asset_path)
85
+ replacement_path = "/#{asset_page.destination_path}"
86
+ replacement_path = Pathname.new(replacement_path).relative_path_from(dirpath).to_s if relative_path
111
87
 
112
- status, headers, response = Rack::Response.new(body, status, headers).finish
88
+ "#{opening_character}#{replacement_path}"
89
+ else
90
+ match
113
91
  end
114
92
  end
115
- [status, headers, response]
93
+
94
+ status, headers, response = Rack::Response.new(body, status, headers).finish
116
95
  end
117
96
  end
97
+ [status, headers, response]
118
98
  end
119
99
  end
120
- end
121
100
 
101
+ end
122
102
 
123
103
  # =================Temp Generate Test data==============================
124
104
  # ["jpg", "png", "gif"].each do |ext|
@@ -1,49 +1,50 @@
1
- # Extensions namespace
2
- module Middleman
3
- module Extensions
4
1
 
5
- # Asset Host module
6
- module AssetHost
2
+ # Asset Host module
3
+ class Middleman::Extensions::AssetHost < ::Middleman::Extension
4
+ option :host, nil, 'The asset host to use, or false for no asset host, or a Proc to determine asset host'
7
5
 
8
- # Setup extension
9
- class << self
6
+ def initialize(app, options_hash={}, &block)
7
+ super
10
8
 
11
- # Once registered
12
- def registered(app, options={})
13
- app.config.define_setting :asset_host, false, 'The asset host to use, or false for no asset host, or a Proc to determine asset host'
9
+ # Backwards compatible API
10
+ app.config.define_setting :asset_host, nil, 'The asset host to use, or false for no asset host, or a Proc to determine asset host'
14
11
 
15
- if options[:host]
16
- config[:asset_host] = options[:host]
12
+ app.compass_config do |config|
13
+ if asset_host = extensions[:asset_host].host
14
+ if asset_host.is_a?(Proc)
15
+ config.asset_host(&asset_host)
16
+ else
17
+ config.asset_host do |asset|
18
+ asset_host
17
19
  end
18
-
19
- # Include methods
20
- app.send :include, InstanceMethods
21
20
  end
22
-
23
- alias :included :registered
24
21
  end
22
+ end
23
+ end
25
24
 
26
- # Asset Host Instance Methods
27
- module InstanceMethods
28
-
29
- # Override default asset url helper to include asset hosts
30
- #
31
- # @param [String] path
32
- # @param [String] prefix
33
- # @return [String]
34
- def asset_url(path, prefix="")
35
- original_output = super
36
- return original_output unless config[:asset_host]
37
-
38
- asset_prefix = if config[:asset_host].is_a?(Proc)
39
- config[:asset_host].call(original_output)
40
- elsif config[:asset_host].is_a?(String)
41
- config[:asset_host]
42
- end
25
+ def host
26
+ app.config[:asset_host] || options[:host]
27
+ end
43
28
 
44
- File.join(asset_prefix, original_output)
45
- end
29
+ helpers do
30
+ # Override default asset url helper to include asset hosts
31
+ #
32
+ # @param [String] path
33
+ # @param [String] prefix
34
+ # @return [String]
35
+ def asset_url(path, prefix="")
36
+ controller = extensions[:asset_host]
37
+
38
+ original_output = super
39
+ return original_output unless controller.host
40
+
41
+ asset_prefix = if controller.host.is_a?(Proc)
42
+ controller.host.call(original_output)
43
+ elsif controller.host.is_a?(String)
44
+ controller.host
46
45
  end
46
+
47
+ File.join(asset_prefix, original_output)
47
48
  end
48
49
  end
49
50
  end