amber 0.2.6 → 0.3.8

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 (129) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +14 -1
  3. data/README.md +88 -19
  4. data/bin/amber +26 -13
  5. data/lib/amber.rb +25 -39
  6. data/lib/amber/cli.rb +25 -1
  7. data/lib/amber/i18n.rb +43 -0
  8. data/lib/amber/render/apache.rb +44 -0
  9. data/lib/amber/render/asset.rb +28 -2
  10. data/lib/amber/render/helpers/blog_helper.rb +35 -0
  11. data/lib/amber/render/helpers/date_helper.rb +14 -0
  12. data/lib/amber/render/helpers/haml_helper.rb +9 -0
  13. data/lib/amber/render/helpers/html_helper.rb +30 -8
  14. data/lib/amber/render/helpers/navigation_helper.rb +31 -32
  15. data/lib/amber/render/layout.rb +2 -1
  16. data/lib/amber/render/template.rb +24 -11
  17. data/lib/amber/render/view.rb +31 -12
  18. data/lib/amber/server.rb +122 -56
  19. data/lib/amber/site.rb +171 -29
  20. data/lib/amber/site_configuration.rb +26 -11
  21. data/lib/amber/static_page.rb +34 -20
  22. data/lib/amber/static_page/filesystem.rb +3 -7
  23. data/lib/amber/static_page/page_properties.rb +7 -0
  24. data/lib/amber/static_page/render.rb +47 -31
  25. data/lib/amber/templates/apache_config.erb +12 -0
  26. data/lib/amber/templates/apache_config_with_prefix.erb +14 -0
  27. data/lib/amber/templates/htaccess.erb +176 -0
  28. data/lib/amber/version.rb +5 -0
  29. data/locales/rails-i18n/af.yml +201 -0
  30. data/locales/rails-i18n/ar.yml +274 -0
  31. data/locales/rails-i18n/az.yml +192 -0
  32. data/locales/rails-i18n/bg.yml +192 -0
  33. data/locales/rails-i18n/bn.yml +175 -0
  34. data/locales/rails-i18n/bs.yml +243 -0
  35. data/locales/rails-i18n/ca.yml +192 -0
  36. data/locales/rails-i18n/cs.yml +210 -0
  37. data/locales/rails-i18n/cy.yml +242 -0
  38. data/locales/rails-i18n/da.yml +198 -0
  39. data/locales/rails-i18n/de-AT.yml +202 -0
  40. data/locales/rails-i18n/de-CH.yml +206 -0
  41. data/locales/rails-i18n/de.yml +202 -0
  42. data/locales/rails-i18n/el.yml +198 -0
  43. data/locales/rails-i18n/en-AU.yml +198 -0
  44. data/locales/rails-i18n/en-CA.yml +207 -0
  45. data/locales/rails-i18n/en-GB.yml +198 -0
  46. data/locales/rails-i18n/en-IE.yml +198 -0
  47. data/locales/rails-i18n/en-IN.yml +198 -0
  48. data/locales/rails-i18n/en-NZ.yml +198 -0
  49. data/locales/rails-i18n/en-US.yml +204 -0
  50. data/locales/rails-i18n/en-ZA.yml +204 -0
  51. data/locales/rails-i18n/en.yml +204 -0
  52. data/locales/rails-i18n/eo.yml +194 -0
  53. data/locales/rails-i18n/es-419.yml +207 -0
  54. data/locales/rails-i18n/es-AR.yml +198 -0
  55. data/locales/rails-i18n/es-CL.yml +192 -0
  56. data/locales/rails-i18n/es-CO.yml +198 -0
  57. data/locales/rails-i18n/es-CR.yml +198 -0
  58. data/locales/rails-i18n/es-EC.yml +204 -0
  59. data/locales/rails-i18n/es-MX.yml +204 -0
  60. data/locales/rails-i18n/es-PA.yml +204 -0
  61. data/locales/rails-i18n/es-PE.yml +177 -0
  62. data/locales/rails-i18n/es-US.yml +198 -0
  63. data/locales/rails-i18n/es-VE.yml +198 -0
  64. data/locales/rails-i18n/es.yml +192 -0
  65. data/locales/rails-i18n/et.yml +192 -0
  66. data/locales/rails-i18n/eu.yml +192 -0
  67. data/locales/rails-i18n/fa.yml +192 -0
  68. data/locales/rails-i18n/fi.yml +192 -0
  69. data/locales/rails-i18n/fr-CA.yml +200 -0
  70. data/locales/rails-i18n/fr-CH.yml +200 -0
  71. data/locales/rails-i18n/fr.yml +214 -0
  72. data/locales/rails-i18n/gl.yml +171 -0
  73. data/locales/rails-i18n/he.yml +194 -0
  74. data/locales/rails-i18n/hi-IN.yml +192 -0
  75. data/locales/rails-i18n/hi.yml +192 -0
  76. data/locales/rails-i18n/hr.yml +236 -0
  77. data/locales/rails-i18n/hu.yml +192 -0
  78. data/locales/rails-i18n/id.yml +193 -0
  79. data/locales/rails-i18n/is.yml +212 -0
  80. data/locales/rails-i18n/iso-639-2/csb.yml +203 -0
  81. data/locales/rails-i18n/iso-639-2/dsb.yml +208 -0
  82. data/locales/rails-i18n/iso-639-2/fur.yml +192 -0
  83. data/locales/rails-i18n/iso-639-2/gsw-CH.yml +196 -0
  84. data/locales/rails-i18n/iso-639-2/hsb.yml +207 -0
  85. data/locales/rails-i18n/iso-639-2/pap-AW.yml +205 -0
  86. data/locales/rails-i18n/iso-639-2/pap-CW.yml +205 -0
  87. data/locales/rails-i18n/iso-639-2/scr.yml +236 -0
  88. data/locales/rails-i18n/it-CH.yml +198 -0
  89. data/locales/rails-i18n/it.yml +204 -0
  90. data/locales/rails-i18n/ja.yml +194 -0
  91. data/locales/rails-i18n/km.yml +54 -0
  92. data/locales/rails-i18n/kn.yml +192 -0
  93. data/locales/rails-i18n/ko.yml +190 -0
  94. data/locales/rails-i18n/lo.yml +227 -0
  95. data/locales/rails-i18n/lt.yml +217 -0
  96. data/locales/rails-i18n/lv.yml +229 -0
  97. data/locales/rails-i18n/mk.yml +198 -0
  98. data/locales/rails-i18n/mn.yml +198 -0
  99. data/locales/rails-i18n/ms.yml +200 -0
  100. data/locales/rails-i18n/nb.yml +205 -0
  101. data/locales/rails-i18n/ne.yml +198 -0
  102. data/locales/rails-i18n/nl.yml +204 -0
  103. data/locales/rails-i18n/nn.yml +201 -0
  104. data/locales/rails-i18n/or.yml +192 -0
  105. data/locales/rails-i18n/pl.yml +236 -0
  106. data/locales/rails-i18n/pt-BR.yml +206 -0
  107. data/locales/rails-i18n/pt.yml +200 -0
  108. data/locales/rails-i18n/rm.yml +223 -0
  109. data/locales/rails-i18n/ro.yml +205 -0
  110. data/locales/rails-i18n/ru.yml +256 -0
  111. data/locales/rails-i18n/sk.yml +206 -0
  112. data/locales/rails-i18n/sl.yml +205 -0
  113. data/locales/rails-i18n/sr.yml +236 -0
  114. data/locales/rails-i18n/sv.yml +192 -0
  115. data/locales/rails-i18n/sw.yml +190 -0
  116. data/locales/rails-i18n/ta.yml +204 -0
  117. data/locales/rails-i18n/th.yml +166 -0
  118. data/locales/rails-i18n/tl.yml +224 -0
  119. data/locales/rails-i18n/tr.yml +204 -0
  120. data/locales/rails-i18n/uk.yml +250 -0
  121. data/locales/rails-i18n/ur.yml +204 -0
  122. data/locales/rails-i18n/uz.yml +250 -0
  123. data/locales/rails-i18n/vi.yml +198 -0
  124. data/locales/rails-i18n/wo.yml +198 -0
  125. data/locales/rails-i18n/zh-CN.yml +203 -0
  126. data/locales/rails-i18n/zh-HK.yml +204 -0
  127. data/locales/rails-i18n/zh-TW.yml +203 -0
  128. data/locales/rails-i18n/zh-YUE.yml +204 -0
  129. metadata +164 -74
@@ -12,9 +12,11 @@ module Amber
12
12
 
13
13
  attr_accessor :title
14
14
  attr_accessor :pagination_size
15
- attr_accessor :mount_points
16
15
  attr_accessor :locales
17
16
  attr_accessor :default_locale
17
+ attr_accessor :path_prefix
18
+ alias :path :path_prefix
19
+ attr_accessor :short_paths
18
20
 
19
21
  attr_accessor :menu
20
22
 
@@ -29,8 +31,13 @@ module Amber
29
31
  attr_accessor :locales_dir
30
32
  attr_accessor :timestamp
31
33
 
34
+ # an array of SiteConfigurations that are attached as sub-sites
35
+ # to this one.
36
+ attr_accessor :children
37
+
32
38
  extend Forwardable
33
- def_delegators :@site, :pages, :find_page, :find_pages, :find_page_by_path, :find_page_by_name, :continue_on_error
39
+ def_delegators :@site, :pages, :find_page, :find_pages, :find_page_by_path,
40
+ :find_page_by_name, :continue_on_error, :root
34
41
 
35
42
  ##
36
43
  ## CLASS METHODS
@@ -48,6 +55,7 @@ module Amber
48
55
  # accepts a file_path to a configuration file.
49
56
  #
50
57
  def initialize(site, root_dir, options={})
58
+ @children = []
51
59
  @site = site
52
60
  @root_dir = File.expand_path(find_in_directory_tree('amber', 'config.rb', root_dir))
53
61
  if @root_dir == '/'
@@ -61,9 +69,6 @@ module Amber
61
69
  @menu_file = config_path('menu.txt')
62
70
  @locales_dir = config_path('locales')
63
71
  @layouts_dir = config_path('layouts')
64
- @path = '/'
65
- @mount_points = []
66
- @mount_points << self
67
72
  @title = "untitled"
68
73
  @pagination_size = 20
69
74
 
@@ -71,15 +76,21 @@ module Amber
71
76
  @menu.load(@menu_file) if @menu_file
72
77
 
73
78
  self.eval
79
+ @path_prefix = options[:path_prefix] if options[:path_prefix]
74
80
  self.cleanup
75
81
 
76
82
  reset_timestamp
77
83
  Render::Layout.load(@layouts_dir)
78
84
  end
79
85
 
80
- #def include_site(directory_source, options={})
81
- # @mount_points << SiteMountPoint.new(self, directory_source, options)
82
- #end
86
+ #
87
+ # map('/path' => '../othersite')
88
+ #
89
+ def map(path_to_directory_source, options={})
90
+ path, root_dir = path_to_directory_source.to_a.first
91
+ config = self.load(@site, root_dir, {:path_prefix => path})
92
+ @site.add_config(config)
93
+ end
83
94
 
84
95
  def cleanup
85
96
  @locale ||= I18n.default_locale
@@ -92,11 +103,15 @@ module Amber
92
103
  nil
93
104
  end
94
105
  }.compact
106
+ if @path_prefix
107
+ @path_prefix.gsub!(%r{^/|/$}, '')
108
+ @path_prefix = nil if @path_prefix == ''
109
+ end
95
110
  end
96
111
 
97
- def pages_changed?
98
- @mount_points.detect {|mp| mp.changed?}
99
- end
112
+ #def pages_changed?
113
+ # self.changed? || @children.detect {|child| child.changed?}
114
+ #end
100
115
 
101
116
  def eval
102
117
  self.instance_eval(File.read(@config_file), @config_file)
@@ -13,9 +13,8 @@ module Amber
13
13
  :name, # the name of the page
14
14
  :file_path, #
15
15
  :parent, # parent page (nil for root page)
16
- :mount_point, # associated SiteConfiguration
17
- :site, # associated Site
18
- :locales, # currently unused
16
+ :config, # associated SiteConfiguration (site might have several)
17
+ :site, # associated Site (only one)
19
18
  :valid # `false` if there is some problem with this page.
20
19
 
21
20
  attr_reader :props # set of page properties (PropertySet)
@@ -28,7 +27,7 @@ module Amber
28
27
 
29
28
  FORBIDDEN_PAGE_CHARS_RE = /[A-Z\.\?\|\[\]\{\}\$\^\*~!@#%&='"<>]/
30
29
 
31
- def initialize(parent, name, file_path=nil)
30
+ def initialize(parent, name, file_path=nil, path_prefix="/")
32
31
  @valid = true
33
32
  @children = PageArray.new # array of StaticPages
34
33
  @nav_title = {} # key is locale
@@ -39,11 +38,11 @@ module Amber
39
38
  # set @parent & @path
40
39
  if parent
41
40
  @parent = parent
42
- @mount_point = @parent.mount_point
41
+ @config = @parent.config
43
42
  @parent.add_child(self)
44
43
  @path = [@parent.path, @name].flatten.compact
45
44
  else
46
- @path = []
45
+ @path = (path_prefix||"").split('/')
47
46
  end
48
47
 
49
48
  if @name =~ FORBIDDEN_PAGE_CHARS_RE
@@ -113,32 +112,47 @@ module Amber
113
112
  @props.prop(*args)
114
113
  end
115
114
 
115
+ #
116
+ # Returns array of locale symbols for all locales with properties set
117
+ # Note: there might be a content for a locale that does not show up in this array,
118
+ # if the content file does not set any properties.
119
+ #
120
+ def locales
121
+ @props.locales
122
+ end
123
+
116
124
  #
117
125
  # returns an array of normalized aliases based on the :alias property
118
126
  # defined for a page.
119
127
  #
120
128
  # aliases are defined with a leading slash for absolute paths, or without a slash
121
129
  # for relative paths. this method converts this to a format that amber uses
122
- # (all absolute, with no leading slash).
123
- #
124
- # currently, we do not maintain per-locale paths or aliases.
130
+ # (all absolute, with no leading slash, as an array instead of a string).
125
131
  #
126
- def aliases
132
+ def aliases(locale=I18n.default_locale)
127
133
  @aliases ||= begin
128
- if @props.alias.nil?
129
- []
130
- else
131
- @props.alias.collect {|alias_path|
132
- if alias_path =~ /^\//
133
- alias_path.sub(/^\//, '')
134
- elsif @parent
135
- (@parent.path + [alias_path]).join('/')
134
+ aliases_hash = Hash.new([])
135
+ @props.locales.each do |locale|
136
+ aliases = @props.prop_without_inheritance(locale, :alias)
137
+ aliases_hash[locale] = begin
138
+ if aliases.nil?
139
+ []
136
140
  else
137
- alias_path
141
+ [aliases].flatten.collect {|alias_path|
142
+ if alias_path =~ /^\//
143
+ alias_path.sub(/^\//, '').split('/')
144
+ elsif @parent
145
+ @parent.path + [alias_path]
146
+ else
147
+ alias_path.split('/')
148
+ end
149
+ }
138
150
  end
139
- }
151
+ end
140
152
  end
153
+ aliases_hash
141
154
  end
155
+ @aliases[locale]
142
156
  end
143
157
 
144
158
  protected
@@ -95,15 +95,9 @@ module Amber
95
95
  # e.g. /home/user/mysite/public/about-us/contact/index.en.html
96
96
  #
97
97
  def destination_file(dest_dir, locale)
98
- if @simple_page
99
- File.join(dest_dir, "#{File.join(@path)}.#{locale}.html")
100
- else
101
- File.join(dest_dir, *@path, "index.#{locale}.html")
102
- end
98
+ File.join(dest_dir, *@path, "index.#{locale}.html")
103
99
  end
104
100
 
105
- private
106
-
107
101
  # e.g. en, de, pt
108
102
  LOCALES_RE = /(?<locale>#{Amber::POSSIBLE_LANGUAGE_CODES.join('|')})/
109
103
  LOCALES_GLOB = "{#{Amber::POSSIBLE_LANGUAGE_CODES.join(',')}}"
@@ -118,6 +112,8 @@ module Amber
118
112
 
119
113
  SIMPLE_FILE_MATCH_RE = lambda {|name| /^(#{Regexp.escape(name)})(\.#{LOCALES_RE})?\.#{PAGE_SUFFIXES_RE}$/ }
120
114
 
115
+ private
116
+
121
117
  #
122
118
  # returns true if the name of a file could be a 'simple' static page
123
119
  # that is not a directory.
@@ -111,6 +111,13 @@ module Amber
111
111
  end
112
112
  end
113
113
 
114
+ #
115
+ # returns an array of locale symbols that are active for this page.
116
+ #
117
+ def locales
118
+ @locales.keys
119
+ end
120
+
114
121
  #
115
122
  # tries to get the value of an inherited variable
116
123
  #
@@ -34,8 +34,26 @@ module Amber
34
34
  def render_to_file(dest_dir, options={})
35
35
  render_content_files(dest_dir, options)
36
36
  render_assets(dest_dir)
37
- if aliases.any?
38
- link_page_aliases(dest_dir)
37
+ @props.locales.each do |locale|
38
+ if aliases(locale).any?
39
+ link_page_aliases(dest_dir, aliases(locale), locale)
40
+ end
41
+ end
42
+ end
43
+
44
+ #
45
+ # creates symlinks for aliases to this page.
46
+ # called by Page#render_to_file and Site#render_short_path_aliases
47
+ #
48
+ def link_page_aliases(dest_dir, alias_paths, locale=I18n.default_locale)
49
+ alias_paths.each do |alias_path|
50
+ alias_file_path = File.join(dest_dir, alias_path)
51
+ #if locale != I18n.default_locale
52
+ # alias_file_path += ".#{locale}"
53
+ #end
54
+ alias_file_path = Pathname.new(alias_file_path)
55
+ page_file_path = Pathname.new(File.join(dest_dir, *@path))
56
+ symlink(page_file_path, alias_file_path)
39
57
  end
40
58
  end
41
59
 
@@ -69,40 +87,38 @@ module Amber
69
87
  end
70
88
  end
71
89
 
72
- # called only by render_to_file
73
- # for now, we only support aliases on pages that are directories, for simplicity sake.
74
- def link_page_aliases(dest_dir)
75
- if @simple_page
76
- Amber.logger.warn { "The page `#{@file_path}` sets a path alias, but currently aliases are only supported for directory-based pages. Skipping." }
90
+ #
91
+ # create a symlink. arguments must be of type Pathname.
92
+ #
93
+ def symlink(from_path, to_path)
94
+ to_path = realpath(to_path)
95
+ target = from_path.relative_path_from(to_path).to_s.sub(/^\.\.\//, '')
96
+ if !to_path.dirname.directory?
97
+ Amber.logger.warn { "On page `#{@file_path}`, the parent directories for alias name `#{to_path}` don't exist. Skipping alias." }
98
+ return
99
+ end
100
+ if to_path.exist? && to_path.symlink?
101
+ File.unlink(to_path)
102
+ end
103
+ if !to_path.exist?
104
+ Amber.logger.debug { "Symlink #{to_path} => #{target}" }
105
+ FileUtils.ln_s(target, to_path)
106
+ end
107
+ end
108
+
109
+ def realpath(pathname)
110
+ dir = pathname.dirname
111
+ if dir.directory? || dir.symlink?
112
+ dir.realpath + pathname.basename
77
113
  else
78
- aliases.each do |alias_path|
79
- alias_path = Pathname.new(File.join(dest_dir, alias_path))
80
- if !File.directory?(File.dirname(alias_path))
81
- Amber.logger.warn { "On page `#{@file_path}`, the parent directories for alias name `#{alias_path}` don't exist. Skipping alias." }
82
- else
83
- page_path = Pathname.new(File.join(dest_dir, *@path))
84
- target = page_path.relative_path_from(alias_path).to_s.sub(/^\.\.\//, '')
85
- if File.exists?(alias_path)
86
- if File.symlink?(alias_path)
87
- File.unlink(alias_path)
88
- Amber.logger.debug { "Alias #{alias_path} => #{target}" }
89
- FileUtils.ln_s(target, alias_path)
90
- else
91
- Amber.logger.warn { "The page `#{@file_path}` sets a path alias, but there is already a file in the way (`#{alias_path}`)" }
92
- end
93
- else
94
- Amber.logger.debug { "Alias #{alias_path} => #{target}" }
95
- FileUtils.ln_s(target, alias_path)
96
- end
97
- end
98
- end
114
+ pathname
99
115
  end
100
116
  end
101
117
 
102
118
  # called only by render_to_file
103
119
  def render_content_files(dest_dir, options)
104
- view = Render::View.new(self, self.mount_point)
105
- @mount_point.locales.each do |file_locale|
120
+ view = Render::View.new(self, @config)
121
+ @config.locales.each do |file_locale|
106
122
  content_file = content_file(file_locale)
107
123
  next unless content_file
108
124
  dest = destination_file(dest_dir, file_locale)
@@ -112,7 +128,7 @@ module Amber
112
128
  if options[:force] || !File.exist?(dest) || File.mtime(content_file) > File.mtime(dest)
113
129
  File.open(dest, 'w') do |f|
114
130
  layout = @props.layout || 'default'
115
- f.write view.render({file: content_file, layout: layout}, {locale: file_locale})
131
+ f.write view.render({page: self, layout: layout}, {locale: file_locale})
116
132
  end
117
133
  end
118
134
  end
@@ -0,0 +1,12 @@
1
+ AccessFileName .htaccess
2
+ DocumentRoot "/<%= @directory %>"
3
+ <Directory "/<%= @directory %>">
4
+ AllowOverride FileInfo Indexes Options=All,MultiViews
5
+ <IfModule !mod_authz_core.c>
6
+ Order deny,allow
7
+ Allow from all
8
+ </IfModule>
9
+ <IfModule mod_authz_core.c>
10
+ Require all granted
11
+ </IfModule>
12
+ </Directory>
@@ -0,0 +1,14 @@
1
+ AccessFileName .htaccess
2
+ AliasMatch ^/[a-z]{2}/<%=@site.path_prefix%>(/.+|/|)$ "/<%=@directory%>/$1"
3
+ Alias /<%=@site.path_prefix%> "/<%=@directory%>/"
4
+
5
+ <Directory "/<%=@directory%>/">
6
+ AllowOverride FileInfo Indexes Options=All,MultiViews
7
+ <IfModule !mod_authz_core.c>
8
+ Order deny,allow
9
+ Allow from all
10
+ </IfModule>
11
+ <IfModule mod_authz_core.c>
12
+ Require all granted
13
+ </IfModule>
14
+ </Directory>
@@ -0,0 +1,176 @@
1
+ ##
2
+ ## AUTO NEGOTIATED LOCALE
3
+ ##
4
+
5
+ LanguagePriority en
6
+ ForceLanguagePriority Prefer Fallback
7
+ DirectoryIndex index
8
+ DirectorySlash Off
9
+ Options +MultiViews
10
+
11
+ ##
12
+ ## REWRITES
13
+ ##
14
+
15
+ Options +FollowSymLinks
16
+ RewriteEngine On
17
+
18
+ <% if @site.path_prefix %>
19
+ <% @path_prefix = Regexp.escape(@site.path_prefix) %>
20
+ RewriteBase /<%= @path_prefix %>/
21
+
22
+ ##
23
+ ## remove trailing slashes (except for paths where we added the slash)
24
+ ##
25
+
26
+ # /path_prefix/foo/bar/ => /path_prefix/foo/bar
27
+ # /en/path_prefix/foo/bar => /en/path_prefix/foo/bar
28
+ # rewrite sees this as:
29
+ # /path_prefix/foo/bar.en.html/ => /path_prefix/foo/bar
30
+ RewriteCond %{QUERY_STRING} !end
31
+ RewriteCond %{REQUEST_URI} ^/([a-z]{2}/)?(<%= @path_prefix %>/)?.+\.html/$
32
+ RewriteRule ^(.+)\.[a-z]{2}\.html/$ /%1%2$1 [R=307,L]
33
+
34
+ # en/path_prefix/blah/ => /en/path_prefix/blah
35
+ RewriteCond %{QUERY_STRING} !end
36
+ RewriteCond %{REQUEST_URI} ^/([a-z]{2})/
37
+ RewriteCond %{REQUEST_URI} !\.html$
38
+ RewriteRule ^(.+)/$ /%1/<%= @path_prefix %>/$1 [R=307,L]
39
+
40
+ # en/path_prefix/ => en/path_prefix
41
+ RewriteCond %{QUERY_STRING} !end
42
+ RewriteCond %{REQUEST_URI} ^/([a-z]{2})/<%= @site.path_prefix %>/$
43
+ RewriteRule ^$ /%1/<%= @path_prefix %> [R=307,L]
44
+
45
+ # path_prefix/ => path_prefix
46
+ RewriteCond %{QUERY_STRING} !end
47
+ RewriteCond %{REQUEST_URI} /$
48
+ RewriteRule ^$ /<%= @path_prefix %> [R=307,L]
49
+
50
+ # path_prefix/blah/ => path_prefix/blah
51
+ RewriteCond %{QUERY_STRING} !end
52
+ RewriteRule ^(.+)/$ $1 [R=307,L]
53
+
54
+ ##
55
+ ## rewrite all paths with a local prefix to use
56
+ ## the appropriate index.{local}.html file
57
+ ##
58
+
59
+ ## /en/prefix_path => /index.en.html
60
+ RewriteCond %{QUERY_STRING} !end
61
+ RewriteCond %{REQUEST_URI} ^/([a-z]{2})/<%= @path_prefix %>$
62
+ RewriteRule ^(.*) index.%1.html?end [L]
63
+
64
+ # /en/path_prefix/blah => /path_prefix/blah/index.en.html
65
+ RewriteCond %{QUERY_STRING} !end
66
+ RewriteCond %{REQUEST_URI} !/$
67
+ RewriteCond %{REQUEST_URI} ^/([a-z]{2})/
68
+ RewriteCond %{REQUEST_FILENAME}/index.%1.html -f
69
+ RewriteRule ^(.*) $1/index.%1.html?end [L]
70
+
71
+ # /de/path_prefix/foo/bar => /path_prefix/foo/bar.de.html
72
+ # rewrite sees this as:
73
+ # /de/path_prefix/foo/bar.en.html => /path_prefix/foo/bar.de.html
74
+ RewriteCond %{QUERY_STRING} !end
75
+ RewriteCond %{REQUEST_URI} !/$
76
+ RewriteCond %{REQUEST_FILENAME} en\.html$
77
+ RewriteCond %{REQUEST_FILENAME} -f
78
+ RewriteCond %{REQUEST_URI} ^/([a-z]{2})/
79
+ RewriteRule ^(.*)?\.en\.html $1.%1.html?end [L]
80
+
81
+ ##
82
+ ## internally simulate a trailing slashes for directories in order
83
+ ## to trigger DirectoryIndex and autonegotiated locale.
84
+ ##
85
+
86
+ # /path_prefix/foo/bar => /path_prefix/foo/bar/
87
+ RewriteCond %{QUERY_STRING} !end
88
+ RewriteCond %{REQUEST_FILENAME} -d
89
+ RewriteRule ^(.*[^/])$ $1/?end [PT]
90
+
91
+ # /path_prefix => /path_prefix/
92
+ RewriteCond %{QUERY_STRING} !end
93
+ RewriteCond %{REQUEST_FILENAME} -d
94
+ RewriteRule ^$ /<%= @path_prefix %>/?end [PT]
95
+
96
+ ##
97
+ ## redirect assets that are locale prefixed
98
+ ## (in order to allow relative paths)
99
+ ##
100
+
101
+ # e.g. /de/foo/assets/style.css => /foo/assets/style.css
102
+ RewriteCond %{QUERY_STRING} !end
103
+ RewriteCond %{REQUEST_FILENAME} -f
104
+ RewriteCond %{REQUEST_URI} ^/([a-z]{2})/<%= @path_prefix %>/
105
+ RewriteRule (.*) /$1 [R=307,L]
106
+
107
+ <% else %>
108
+ RewriteBase /
109
+
110
+ ##
111
+ ## remove trailing slashes (except for paths where we added the slash)
112
+ ##
113
+
114
+ # /en/ => /en
115
+ RewriteCond %{QUERY_STRING} !end
116
+ RewriteRule ^([a-z]{2})/$ /$1 [R=307,L]
117
+
118
+ # /en/aaa/ => /en/aaa
119
+ RewriteCond %{QUERY_STRING} !end
120
+ RewriteCond %{REQUEST_URI} ^/([a-z]{2})/
121
+ RewriteCond %{REQUEST_URI} !\.html$
122
+ RewriteRule ^(.+)/$ /$1 [R=307,L]
123
+
124
+ # /foo/bar.en.html/ => /foo/bar
125
+ RewriteCond %{QUERY_STRING} !end
126
+ RewriteCond %{REQUEST_URI} \.html/$
127
+ RewriteRule ^(.+)\.[a-z]{2}\.html/$ $1 [R=307,L]
128
+
129
+ # /foo/bar/ => /foo/blah
130
+ RewriteCond %{QUERY_STRING} !end
131
+ RewriteRule ^(.+)/$ $1 [R=307,L]
132
+
133
+ ##
134
+ ## rewrite all paths with a local prefix to use
135
+ ## the appropriate index.{local}.html file or
136
+ ## filename.{local}.html file.
137
+ ##
138
+
139
+ # /en => /index.en.html
140
+ RewriteCond %{QUERY_STRING} !end
141
+ RewriteCond %{DOCUMENT_ROOT}/index.$1.html -f
142
+ RewriteCond %{REQUEST_URI} ^/([a-z]{2})$
143
+ RewriteRule ^(.*) /index.%1.html?end [L]
144
+
145
+ # /en/aaa => /aaa/index.en.html
146
+ RewriteCond %{QUERY_STRING} !end
147
+ RewriteCond %{DOCUMENT_ROOT}/$2/index.$1.html -f
148
+ RewriteRule ^([a-z]{2})/(.*) /$2/index.$1.html?end [L]
149
+
150
+ # /de/foo/bar => /foo/bar.de.html
151
+ RewriteCond %{QUERY_STRING} !end
152
+ RewriteCond %{DOCUMENT_ROOT}/$2.$1.html -f
153
+ RewriteRule ^([a-z]{2})/(.*) /$2.$1.html?end [L]
154
+
155
+ ##
156
+ ## internally simulate a trailing slashes for directories in order
157
+ ## to trigger DirectoryIndex and autonegotiated locale.
158
+ ##
159
+
160
+ # /foo/bar => /foo/bar/
161
+ RewriteCond %{QUERY_STRING} !end
162
+ RewriteCond %{DOCUMENT_ROOT}/$1 -d
163
+ RewriteRule ^(.*[^/])$ /$1/?end [PT]
164
+
165
+ ##
166
+ ## redirect assets that are locale prefixed
167
+ ## (in order to allow relative paths)
168
+ ##
169
+
170
+ # e.g. /de/foo/assets/style.css => /foo/assets/style.css
171
+ RewriteCond %{QUERY_STRING} !end
172
+ RewriteCond %{DOCUMENT_ROOT}/$2 -f
173
+ RewriteRule ^([a-z]{2})/(.*) /$2 [R=307,L]
174
+
175
+ <% end %>
176
+