html5 0.1.0 → 0.10.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 (98) hide show
  1. data/History.txt +9 -2
  2. data/Manifest.txt +61 -2
  3. data/README +41 -5
  4. data/Rakefile.rb +22 -6
  5. data/{parse.rb → bin/html5} +11 -11
  6. data/lib/core_ext/string.rb +17 -0
  7. data/lib/html5/constants.rb +228 -0
  8. data/lib/html5/filters/iso639codes.rb +752 -0
  9. data/lib/html5/filters/rfc2046.rb +30 -0
  10. data/lib/html5/filters/rfc3987.rb +89 -0
  11. data/lib/html5/filters/validator.rb +830 -0
  12. data/lib/html5/html5parser.rb +25 -25
  13. data/lib/html5/html5parser/after_body_phase.rb +3 -3
  14. data/lib/html5/html5parser/after_frameset_phase.rb +3 -4
  15. data/lib/html5/html5parser/after_head_phase.rb +6 -6
  16. data/lib/html5/html5parser/before_head_phase.rb +1 -1
  17. data/lib/html5/html5parser/in_body_phase.rb +54 -48
  18. data/lib/html5/html5parser/in_caption_phase.rb +7 -6
  19. data/lib/html5/html5parser/in_cell_phase.rb +3 -3
  20. data/lib/html5/html5parser/in_column_group_phase.rb +1 -1
  21. data/lib/html5/html5parser/in_frameset_phase.rb +5 -5
  22. data/lib/html5/html5parser/in_head_phase.rb +10 -10
  23. data/lib/html5/html5parser/in_row_phase.rb +4 -2
  24. data/lib/html5/html5parser/in_select_phase.rb +7 -6
  25. data/lib/html5/html5parser/in_table_body_phase.rb +8 -5
  26. data/lib/html5/html5parser/in_table_phase.rb +12 -7
  27. data/lib/html5/html5parser/initial_phase.rb +5 -6
  28. data/lib/html5/html5parser/phase.rb +5 -9
  29. data/lib/html5/html5parser/root_element_phase.rb +1 -2
  30. data/lib/html5/html5parser/trailing_end_phase.rb +3 -3
  31. data/lib/html5/inputstream.rb +25 -31
  32. data/lib/html5/liberalxmlparser.rb +2 -2
  33. data/lib/html5/sanitizer.rb +6 -6
  34. data/lib/html5/serializer/htmlserializer.rb +2 -3
  35. data/lib/html5/sniffer.rb +45 -0
  36. data/lib/html5/tokenizer.rb +57 -59
  37. data/lib/html5/treebuilders/rexml.rb +7 -6
  38. data/lib/html5/treebuilders/simpletree.rb +1 -1
  39. data/lib/html5/treewalkers/base.rb +8 -0
  40. data/lib/html5/version.rb +3 -0
  41. data/testdata/encoding/chardet/test_big5.txt +51 -0
  42. data/testdata/encoding/test-yahoo-jp.dat +10 -0
  43. data/testdata/encoding/tests1.dat +394 -0
  44. data/testdata/encoding/tests2.dat +81 -0
  45. data/testdata/sanitizer/tests1.dat +416 -0
  46. data/testdata/serializer/core.test +104 -0
  47. data/testdata/serializer/injectmeta.test +65 -0
  48. data/testdata/serializer/optionaltags.test +900 -0
  49. data/testdata/serializer/options.test +60 -0
  50. data/testdata/serializer/whitespace.test +51 -0
  51. data/testdata/sites/google-results.htm +1 -0
  52. data/testdata/sites/python-ref-import.htm +1 -0
  53. data/testdata/sites/web-apps-old.htm +1 -0
  54. data/testdata/sites/web-apps.htm +34275 -0
  55. data/testdata/sniffer/htmlOrFeed.json +43 -0
  56. data/testdata/tokenizer/contentModelFlags.test +48 -0
  57. data/testdata/tokenizer/entities.test +2339 -0
  58. data/testdata/tokenizer/escapeFlag.test +21 -0
  59. data/testdata/tokenizer/test1.test +172 -0
  60. data/testdata/tokenizer/test2.test +129 -0
  61. data/testdata/tokenizer/test3.test +367 -0
  62. data/testdata/tokenizer/test4.test +198 -0
  63. data/testdata/tree-construction/tests1.dat +1950 -0
  64. data/testdata/tree-construction/tests2.dat +773 -0
  65. data/testdata/tree-construction/tests3.dat +270 -0
  66. data/testdata/tree-construction/tests4.dat +60 -0
  67. data/testdata/tree-construction/tests5.dat +175 -0
  68. data/testdata/tree-construction/tests6.dat +196 -0
  69. data/testdata/validator/attributes.test +1035 -0
  70. data/testdata/validator/base-href-attribute.test +787 -0
  71. data/testdata/validator/base-target-attribute.test +35 -0
  72. data/testdata/validator/blockquote-cite-attribute.test +7 -0
  73. data/testdata/validator/classattribute.test +152 -0
  74. data/testdata/validator/contenteditableattribute.test +59 -0
  75. data/testdata/validator/contextmenuattribute.test +115 -0
  76. data/testdata/validator/dirattribute.test +59 -0
  77. data/testdata/validator/draggableattribute.test +63 -0
  78. data/testdata/validator/html-xmlns-attribute.test +23 -0
  79. data/testdata/validator/idattribute.test +115 -0
  80. data/testdata/validator/inputattributes.test +2795 -0
  81. data/testdata/validator/irrelevantattribute.test +63 -0
  82. data/testdata/validator/langattribute.test +5579 -0
  83. data/testdata/validator/li-value-attribute.test +7 -0
  84. data/testdata/validator/link-href-attribute.test +7 -0
  85. data/testdata/validator/link-hreflang-attribute.test +7 -0
  86. data/testdata/validator/link-rel-attribute.test +271 -0
  87. data/testdata/validator/ol-start-attribute.test +7 -0
  88. data/testdata/validator/starttags.test +375 -0
  89. data/testdata/validator/style-scoped-attribute.test +7 -0
  90. data/testdata/validator/tabindexattribute.test +79 -0
  91. data/tests/preamble.rb +7 -17
  92. data/tests/test_encoding.rb +1 -1
  93. data/tests/test_lxp.rb +16 -0
  94. data/tests/test_parser.rb +2 -2
  95. data/tests/test_sniffer.rb +27 -0
  96. data/tests/test_treewalkers.rb +41 -22
  97. data/tests/test_validator.rb +31 -0
  98. metadata +65 -6
@@ -46,8 +46,8 @@ module HTML5
46
46
  @tree = TreeBuilders::REXML::TreeBuilder
47
47
 
48
48
  options.each {|name, value| instance_variable_set("@#{name}", value) }
49
- @lowercase_attr_name = nil unless instance_variable_defined?(:@lowercase_attr_name)
50
- @lowercase_element_name = nil unless instance_variable_defined?(:@lowercase_element_name)
49
+ @lowercase_attr_name = nil unless instance_variables.include?("@lowercase_attr_name")
50
+ @lowercase_element_name = nil unless instance_variables.include?("@lowercase_element_name")
51
51
 
52
52
  @tree = @tree.new
53
53
 
@@ -69,15 +69,15 @@ module HTML5
69
69
 
70
70
  if inner_html
71
71
  case @inner_html = container.downcase
72
- when 'title', 'textarea'
73
- @tokenizer.content_model_flag = :RCDATA
74
- when 'style', 'script', 'xmp', 'iframe', 'noembed', 'noframes', 'noscript'
75
- @tokenizer.content_model_flag = :CDATA
76
- when 'plaintext'
77
- @tokenizer.content_model_flag = :PLAINTEXT
78
- else
72
+ when 'title', 'textarea'
73
+ @tokenizer.content_model_flag = :RCDATA
74
+ when 'style', 'script', 'xmp', 'iframe', 'noembed', 'noframes', 'noscript'
75
+ @tokenizer.content_model_flag = :CDATA
76
+ when 'plaintext'
77
+ @tokenizer.content_model_flag = :PLAINTEXT
78
+ else
79
79
  # content_model_flag already is PCDATA
80
- #@tokenizer.content_model_flag = :PCDATA
80
+ @tokenizer.content_model_flag = :PCDATA
81
81
  end
82
82
 
83
83
  @phase = @phases[:rootElement]
@@ -100,17 +100,17 @@ module HTML5
100
100
  method = 'process%s' % token[:type]
101
101
 
102
102
  case token[:type]
103
- when :Characters, :SpaceCharacters, :Comment
104
- @phase.send method, token[:data]
105
- when :StartTag
106
- @phase.send method, token[:name], token[:data]
107
- when :EndTag
108
- @phase.send method, token[:name]
109
- when :Doctype
110
- @phase.send method, token[:name], token[:publicId],
111
- token[:systemId], token[:correct]
112
- else
113
- parse_error(token[:data])
103
+ when :Characters, :SpaceCharacters, :Comment
104
+ @phase.send method, token[:data]
105
+ when :StartTag
106
+ @phase.send method, token[:name], token[:data]
107
+ when :EndTag
108
+ @phase.send method, token[:name]
109
+ when :Doctype
110
+ @phase.send method, token[:name], token[:publicId],
111
+ token[:systemId], token[:correct]
112
+ else
113
+ parse_error(token[:data], token[:datavars])
114
114
  end
115
115
  end
116
116
 
@@ -147,9 +147,9 @@ module HTML5
147
147
  @tree.get_fragment
148
148
  end
149
149
 
150
- def parse_error(data = 'XXX ERROR MESSAGE NEEDED')
150
+ def parse_error(code = 'XXX-undefined-error', data = {})
151
151
  # XXX The idea is to make data mandatory.
152
- @errors.push([@tokenizer.stream.position, data])
152
+ @errors.push([@tokenizer.stream.position, code, data])
153
153
  raise ParseError if @strict
154
154
  end
155
155
 
@@ -163,7 +163,7 @@ module HTML5
163
163
  # thing and if it doesn't it's wrong for everyone.
164
164
 
165
165
  unless VOID_ELEMENTS.include?(token[:name])
166
- parse_error(_('Solidus (/) incorrectly placed in tag.'))
166
+ parse_error("incorrectly-placed-solidus")
167
167
  end
168
168
 
169
169
  token[:type] = :StartTag
@@ -181,7 +181,7 @@ module HTML5
181
181
  end
182
182
 
183
183
  elsif token[:type] == :EndTag
184
- parse_error(_('End tag contains unexpected attributes.')) unless token[:data].empty?
184
+ parse_error("attributes-in-end-tag") unless token[:data].empty?
185
185
  token[:name] = token[:name].downcase
186
186
  end
187
187
 
@@ -12,13 +12,13 @@ module HTML5
12
12
  end
13
13
 
14
14
  def processCharacters(data)
15
- parse_error(_('Unexpected non-space characters in the after body phase.'))
15
+ parse_error("unexpected-char-after-body")
16
16
  @parser.phase = @parser.phases[:inBody]
17
17
  @parser.phase.processCharacters(data)
18
18
  end
19
19
 
20
20
  def processStartTag(name, attributes)
21
- parse_error(_("Unexpected start tag token (#{name}) in the after body phase."))
21
+ parse_error("unexpected-start-tag-after-body", {"name" => name})
22
22
  @parser.phase = @parser.phases[:inBody]
23
23
  @parser.phase.processStartTag(name, attributes)
24
24
  end
@@ -37,7 +37,7 @@ module HTML5
37
37
  end
38
38
 
39
39
  def endTagOther(name)
40
- parse_error(_("Unexpected end tag token (#{name}) in the after body phase."))
40
+ parse_error("unexpected-end-tag-after-body", {"name" => name})
41
41
  @parser.phase = @parser.phases[:inBody]
42
42
  @parser.phase.processEndTag(name)
43
43
  end
@@ -10,7 +10,7 @@ module HTML5
10
10
  handle_end 'html'
11
11
 
12
12
  def processCharacters(data)
13
- parse_error(_('Unexpected non-space characters in the after frameset phase. Ignored.'))
13
+ parse_error("unexpected-char-after-frameset")
14
14
  end
15
15
 
16
16
  def startTagNoframes(name, attributes)
@@ -18,7 +18,7 @@ module HTML5
18
18
  end
19
19
 
20
20
  def startTagOther(name, attributes)
21
- parse_error(_("Unexpected start tag (#{name}) in the after frameset phase. Ignored."))
21
+ parse_error("unexpected-start-tag-after-frameset", {"name" => name})
22
22
  end
23
23
 
24
24
  def endTagHtml(name)
@@ -27,8 +27,7 @@ module HTML5
27
27
  end
28
28
 
29
29
  def endTagOther(name)
30
- parse_error(_("Unexpected end tag (#{name}) in the after frameset phase. Ignored."))
30
+ parse_error("unexpected-end-tag-after-frameset", {"name" => name})
31
31
  end
32
-
33
32
  end
34
33
  end
@@ -6,12 +6,12 @@ module HTML5
6
6
  handle_start 'html', 'body', 'frameset', %w( base link meta script style title ) => 'FromHead'
7
7
 
8
8
  def process_eof
9
- anythingElse
9
+ anything_else
10
10
  @parser.phase.process_eof
11
11
  end
12
12
 
13
13
  def processCharacters(data)
14
- anythingElse
14
+ anything_else
15
15
  @parser.phase.processCharacters(data)
16
16
  end
17
17
 
@@ -26,22 +26,22 @@ module HTML5
26
26
  end
27
27
 
28
28
  def startTagFromHead(name, attributes)
29
- parse_error(_("Unexpected start tag (#{name}) that can be in head. Moved."))
29
+ parse_error("unexpected-start-tag-out-of-my-head", {"name" => name})
30
30
  @parser.phase = @parser.phases[:inHead]
31
31
  @parser.phase.processStartTag(name, attributes)
32
32
  end
33
33
 
34
34
  def startTagOther(name, attributes)
35
- anythingElse
35
+ anything_else
36
36
  @parser.phase.processStartTag(name, attributes)
37
37
  end
38
38
 
39
39
  def processEndTag(name)
40
- anythingElse
40
+ anything_else
41
41
  @parser.phase.processEndTag(name)
42
42
  end
43
43
 
44
- def anythingElse
44
+ def anything_else
45
45
  @tree.insert_element('body', {})
46
46
  @parser.phase = @parser.phases[:inBody]
47
47
  end
@@ -34,7 +34,7 @@ module HTML5
34
34
  end
35
35
 
36
36
  def endTagOther(name)
37
- parse_error(_("Unexpected end tag (#{name}) after the (implied) root element."))
37
+ parse_error("end-tag-after-implied-root", {"name" => name})
38
38
  end
39
39
 
40
40
  end
@@ -6,45 +6,45 @@ module HTML5
6
6
  # http://www.whatwg.org/specs/web-apps/current-work/#in-body
7
7
 
8
8
  handle_start 'html'
9
- handle_start %w( base link meta script style ) => 'ProcessInHead'
9
+ handle_start %w(base link meta script style) => 'ProcessInHead'
10
10
  handle_start 'title'
11
11
 
12
12
  handle_start 'body', 'form', 'plaintext', 'a', 'button', 'xmp', 'table', 'hr', 'image'
13
13
 
14
- handle_start 'input', 'textarea', 'select', 'isindex', %w( marquee object )
14
+ handle_start 'input', 'textarea', 'select', 'isindex', %w(marquee object)
15
15
 
16
- handle_start %w( li dd dt ) => 'ListItem'
17
-
18
- handle_start %w( address blockquote center dir div dl fieldset listing menu ol p pre ul ) => 'CloseP'
16
+ handle_start %w(li dd dt) => 'ListItem'
19
17
 
20
- handle_start %w( b big em font i s small strike strong tt u ) => 'Formatting'
18
+ handle_start %w(address blockquote center dir div dl fieldset listing menu ol p pre ul) => 'CloseP'
19
+
20
+ handle_start %w(b big em font i s small strike strong tt u) => 'Formatting'
21
21
  handle_start 'nobr'
22
22
 
23
- handle_start %w( area basefont bgsound br embed img param spacer wbr ) => 'VoidFormatting'
23
+ handle_start %w(area basefont bgsound br embed img param spacer wbr) => 'VoidFormatting'
24
24
 
25
- handle_start %w( iframe noembed noframes noscript ) => 'Cdata', HEADING_ELEMENTS => 'Heading'
25
+ handle_start %w(iframe noembed noframes noscript) => 'Cdata', HEADING_ELEMENTS => 'Heading'
26
26
 
27
- handle_start %w( caption col colgroup frame frameset head option optgroup tbody td tfoot th thead tr ) => 'Misplaced'
27
+ handle_start %w(caption col colgroup frame frameset head option optgroup tbody td tfoot th thead tr) => 'Misplaced'
28
28
 
29
- handle_start %w( event-source section nav article aside header footer datagrid command ) => 'New'
29
+ handle_start %w(event-source section nav article aside header footer datagrid command) => 'New'
30
30
 
31
- handle_end 'p', 'body', 'html', 'form', %w( button marquee object ), %w( dd dt li ) => 'ListItem'
31
+ handle_end 'p', 'body', 'html', 'form', %w(button marquee object), %w(dd dt li) => 'ListItem'
32
32
 
33
- handle_end %w( address blockquote center div dl fieldset listing menu ol pre ul ) => 'Block'
33
+ handle_end %w(address blockquote center div dl fieldset listing menu ol pre ul) => 'Block'
34
34
 
35
35
  handle_end HEADING_ELEMENTS => 'Heading'
36
36
 
37
- handle_end %w( a b big em font i nobr s small strike strong tt u ) => 'Formatting'
37
+ handle_end %w(a b big em font i nobr s small strike strong tt u) => 'Formatting'
38
38
 
39
- handle_end %w( head frameset select optgroup option table caption colgroup col thead tfoot tbody tr td th ) => 'Misplaced'
39
+ handle_end %w(head frameset select optgroup option table caption colgroup col thead tfoot tbody tr td th) => 'Misplaced'
40
40
 
41
41
  handle_end 'br'
42
42
 
43
- handle_end %w( area basefont bgsound embed hr image img input isindex param spacer wbr frame ) => 'None'
43
+ handle_end %w(area basefont bgsound embed hr image img input isindex param spacer wbr frame) => 'None'
44
44
 
45
- handle_end %w( noframes noscript noembed textarea xmp iframe ) => 'CdataTextAreaXmp'
45
+ handle_end %w(noframes noscript noembed textarea xmp iframe ) => 'CdataTextAreaXmp'
46
46
 
47
- handle_end %w( event-source section nav article aside header footer datagrid command ) => 'New'
47
+ handle_end %w(event-source section nav article aside header footer datagrid command) => 'New'
48
48
 
49
49
  def initialize(parser, tree)
50
50
  super(parser, tree)
@@ -100,14 +100,14 @@ module HTML5
100
100
  end
101
101
 
102
102
  def startTagTitle(name, attributes)
103
- parse_error(_("Unexpected start tag (#{name}) that belongs in the head. Moved."))
103
+ parse_error("unexpected-start-tag-out-of-my-head", {"name" => name})
104
104
  @parser.phases[:inHead].processStartTag(name, attributes)
105
105
  end
106
106
 
107
107
  def startTagBody(name, attributes)
108
- parse_error(_('Unexpected start tag (body).'))
108
+ parse_error("unexpected-start-tag", {"name" => "body"})
109
109
 
110
- if (@tree.open_elements.length == 1 || @tree.open_elements[1].name != 'body')
110
+ if @tree.open_elements.length == 1 || @tree.open_elements[1].name != 'body'
111
111
  assert @parser.inner_html
112
112
  else
113
113
  attributes.each do |attr, value|
@@ -126,11 +126,11 @@ module HTML5
126
126
 
127
127
  def startTagForm(name, attributes)
128
128
  if @tree.formPointer
129
- parse_error(_('Unexpected start tag (form). Ignored.'))
129
+ parse_error("unexpected-start-tag", {"name" => name})
130
130
  else
131
131
  endTagP('p') if in_scope?('p')
132
132
  @tree.insert_element(name, attributes)
133
- @tree.formPointer = @tree.open_elements[-1]
133
+ @tree.formPointer = @tree.open_elements.last
134
134
  end
135
135
  end
136
136
 
@@ -143,7 +143,10 @@ module HTML5
143
143
  if stopName.include?(node.name)
144
144
  poppedNodes = (0..i).collect { @tree.open_elements.pop }
145
145
  if i >= 1
146
- parse_error(_("Missing end tag%s (%s)" % [(i>1 ? 's' : ''), poppedNodes.reverse.map{|item| item.name}.join(', ')]))
146
+ parse_error(
147
+ i == 1 ? "missing-end-tag" : "missing-end-tags",
148
+ {"name" => poppedNodes[0..-1].collect{|n| n.name}.join(", ")})
149
+
147
150
  end
148
151
  break
149
152
  end
@@ -169,7 +172,7 @@ module HTML5
169
172
  # Uncomment the following for IE7 behavior:
170
173
  # HEADING_ELEMENTS.each do |element|
171
174
  # if in_scope?(element)
172
- # parse_error(_("Unexpected start tag (#{name})."))
175
+ # parse_error("unexpected-start-tag", {"name" => name})
173
176
  #
174
177
  # remove_open_elements_until do |element|
175
178
  # HEADING_ELEMENTS.include?(element.name)
@@ -183,7 +186,7 @@ module HTML5
183
186
 
184
187
  def startTagA(name, attributes)
185
188
  if afeAElement = @tree.elementInActiveFormattingElements('a')
186
- parse_error(_('Unexpected start tag (a) implies end tag (a).'))
189
+ parse_error("unexpected-start-tag-implies-end-tag", {"startName" => "a", "endName" => "a"})
187
190
  endTagFormatting('a')
188
191
  @tree.open_elements.delete(afeAElement) if @tree.open_elements.include?(afeAElement)
189
192
  @tree.activeFormattingElements.delete(afeAElement) if @tree.activeFormattingElements.include?(afeAElement)
@@ -200,7 +203,7 @@ module HTML5
200
203
  def startTagNobr(name, attributes)
201
204
  @tree.reconstructActiveFormattingElements
202
205
  if in_scope?('nobr')
203
- parse_error(_('Unexpected start tag (nobr) implies end tag (nobr).'))
206
+ parse_error("unexpected-start-tag-implies-end-tag", {"startName" => "nobr", "endName" => "nobr"})
204
207
  processEndTag('nobr')
205
208
  # XXX Need tests that trigger the following
206
209
  @tree.reconstructActiveFormattingElements
@@ -210,7 +213,7 @@ module HTML5
210
213
 
211
214
  def startTagButton(name, attributes)
212
215
  if in_scope?('button')
213
- parse_error(_('Unexpected start tag (button) implied end tag (button).'))
216
+ parse_error("unexpected-start-tag-implies-end-tag", {"startName" => "button", "endName" => "button"})
214
217
  processEndTag('button')
215
218
  @parser.phase.processStartTag(name, attributes)
216
219
  else
@@ -252,7 +255,7 @@ module HTML5
252
255
 
253
256
  def startTagImage(name, attributes)
254
257
  # No really...
255
- parse_error(_('Unexpected start tag (image). Treated as img.'))
258
+ parse_error("unexpected-start-tag-treated-as", {"originalName" => "image", "newName" => "img"})
256
259
  processStartTag('img', attributes)
257
260
  end
258
261
 
@@ -267,7 +270,7 @@ module HTML5
267
270
  end
268
271
 
269
272
  def startTagIsindex(name, attributes)
270
- parse_error(_("Unexpected start tag isindex. Don't use it!"))
273
+ parse_error("deprecated-tag", {"name" => "isindex"})
271
274
  return if @tree.formPointer
272
275
  processStartTag('form', {})
273
276
  processStartTag('hr', {})
@@ -310,13 +313,13 @@ module HTML5
310
313
  # "caption", "col", "colgroup", "frame", "frameset", "head",
311
314
  # "option", "optgroup", "tbody", "td", "tfoot", "th", "thead",
312
315
  # "tr", "noscript"
313
- parse_error(_("Unexpected start tag (#{name}). Ignored."))
316
+ parse_error("unexpected-start-tag-ignored", {"name" => name})
314
317
  end
315
318
 
316
319
  def startTagNew(name, attributes)
317
320
  # New HTML5 elements, "event-source", "section", "nav",
318
321
  # "article", "aside", "header", "footer", "datagrid", "command"
319
- sys.stderr.write("Warning: Undefined behaviour for start tag #{name}")
322
+ # $stderr.puts("Warning: Undefined behaviour for start tag #{name}")
320
323
  startTagOther(name, attributes)
321
324
  #raise NotImplementedError
322
325
  end
@@ -328,7 +331,7 @@ module HTML5
328
331
 
329
332
  def endTagP(name)
330
333
  @tree.generateImpliedEndTags('p') if in_scope?('p')
331
- parse_error(_('Unexpected end tag (p).')) unless @tree.open_elements.last.name == 'p'
334
+ parse_error("unexpected-end-tag", {"name" => "p"}) unless @tree.open_elements.last.name == 'p'
332
335
  if in_scope?('p')
333
336
  @tree.open_elements.pop while in_scope?('p')
334
337
  else
@@ -347,7 +350,9 @@ module HTML5
347
350
  return
348
351
  end
349
352
  unless @tree.open_elements.last.name == 'body'
350
- parse_error(_("Unexpected end tag (body). Missing end tag (#{@tree.open_elements[-1].name})."))
353
+ parse_error("expected-one-end-tag-but-got-another",
354
+ {"expectedName" => "body",
355
+ "gotName" => @tree.open_elements.last.name})
351
356
  end
352
357
  @parser.phase = @parser.phases[:afterBody]
353
358
  end
@@ -364,7 +369,7 @@ module HTML5
364
369
  @tree.generateImpliedEndTags if in_scope?(name)
365
370
 
366
371
  unless @tree.open_elements.last.name == name
367
- parse_error(_("End tag (#{name}) seen too early. Expected other end tag."))
372
+ parse_error("end-tag-too-early", {"name" => name})
368
373
  end
369
374
 
370
375
  if in_scope?(name)
@@ -377,7 +382,7 @@ module HTML5
377
382
  @tree.generateImpliedEndTags
378
383
  end
379
384
  if @tree.open_elements.last.name != name
380
- parse_error(_("End tag (form) seen too early. Ignored."))
385
+ parse_error("end-tag-too-early-ignored", {"name" => "form"})
381
386
  else
382
387
  @tree.open_elements.pop
383
388
  end
@@ -389,7 +394,7 @@ module HTML5
389
394
  @tree.generateImpliedEndTags(name) if in_scope?(name)
390
395
 
391
396
  unless @tree.open_elements.last.name == name
392
- parse_error(_("End tag (#{name}) seen too early. " + 'Expected other end tag.'))
397
+ parse_error("end-tag-too-early", {"name" => name})
393
398
  end
394
399
 
395
400
  remove_open_elements_until(name) if in_scope?(name)
@@ -404,7 +409,7 @@ module HTML5
404
409
  end
405
410
 
406
411
  unless @tree.open_elements.last.name == name
407
- parse_error(_("Unexpected end tag (#{name}). Expected other end tag."))
412
+ parse_error("end-tag-too-early", {"name" => name})
408
413
  end
409
414
 
410
415
  HEADING_ELEMENTS.each do |element|
@@ -423,18 +428,18 @@ module HTML5
423
428
  # Step 1 paragraph 1
424
429
  afeElement = @tree.elementInActiveFormattingElements(name)
425
430
  if !afeElement or (@tree.open_elements.include?(afeElement) && !in_scope?(afeElement.name))
426
- parse_error(_("End tag (#{name}) violates step 1, paragraph 1 of the adoption agency algorithm."))
431
+ parse_error("adoption-agency-1.1", {"name" => name})
427
432
  return
428
433
  # Step 1 paragraph 2
429
434
  elsif not @tree.open_elements.include?(afeElement)
430
- parse_error(_("End tag (#{name}) violates step 1, paragraph 2 of the adoption agency algorithm."))
435
+ parse_error("adoption-agency-1.2", {"name" => name})
431
436
  @tree.activeFormattingElements.delete(afeElement)
432
437
  return
433
438
  end
434
439
 
435
440
  # Step 1 paragraph 3
436
441
  if afeElement != @tree.open_elements.last
437
- parse_error(_("End tag (#{name}) violates step 1, paragraph 3 of the adoption agency algorithm."))
442
+ parse_error("adoption-agency-1.3", {"name" => name})
438
443
  end
439
444
 
440
445
  # Step 2
@@ -531,7 +536,7 @@ module HTML5
531
536
  @tree.generateImpliedEndTags if in_scope?(name)
532
537
 
533
538
  unless @tree.open_elements.last.name == name
534
- parse_error(_("Unexpected end tag (#{name}). Expected other end tag first."))
539
+ parse_error("end-tag-too-early", {"name" => name})
535
540
  end
536
541
 
537
542
  if in_scope?(name)
@@ -543,11 +548,12 @@ module HTML5
543
548
 
544
549
  def endTagMisplaced(name)
545
550
  # This handles elements with end tags in other insertion modes.
546
- parse_error(_("Unexpected end tag (#{name}). Ignored."))
551
+ parse_error("unexpected-end-tag", {"name" => name})
547
552
  end
548
553
 
549
554
  def endTagBr(name)
550
- parse_error(_("Unexpected end tag (br). Treated as br element."))
555
+ parse_error("unexpected-end-tag-treated-as",
556
+ {"originalName" => "br", "newName" => "br element"})
551
557
  @tree.reconstructActiveFormattingElements
552
558
  @tree.insert_element(name, {})
553
559
  @tree.open_elements.pop()
@@ -555,21 +561,21 @@ module HTML5
555
561
 
556
562
  def endTagNone(name)
557
563
  # This handles elements with no end tag.
558
- parse_error(_("This tag (#{name}) has no end tag"))
564
+ parse_error("no-end-tag", {"name" => name})
559
565
  end
560
566
 
561
567
  def endTagCdataTextAreaXmp(name)
562
568
  if @tree.open_elements.last.name == name
563
569
  @tree.open_elements.pop
564
570
  else
565
- parse_error(_("Unexpected end tag (#{name}). Ignored."))
571
+ parse_error("unexpected-end-tag", {"name" => name})
566
572
  end
567
573
  end
568
574
 
569
575
  def endTagNew(name)
570
576
  # New HTML5 elements, "event-source", "section", "nav",
571
577
  # "article", "aside", "header", "footer", "datagrid", "command"
572
- STDERR.puts "Warning: Undefined behaviour for end tag #{name}"
578
+ # STDERR.puts "Warning: Undefined behaviour for end tag #{name}"
573
579
  endTagOther(name)
574
580
  #raise NotImplementedError
575
581
  end
@@ -581,7 +587,7 @@ module HTML5
581
587
  @tree.generateImpliedEndTags
582
588
 
583
589
  unless @tree.open_elements.last.name == name
584
- parse_error(_("Unexpected end tag (#{name})."))
590
+ parse_error("unexpected-end-tag", {"name" => name})
585
591
  end
586
592
 
587
593
  remove_open_elements_until {|element| element == node }
@@ -589,7 +595,7 @@ module HTML5
589
595
  break
590
596
  else
591
597
  if (SPECIAL_ELEMENTS + SCOPING_ELEMENTS).include?(node.name)
592
- parse_error(_("Unexpected end tag (#{name}). Ignored."))
598
+ parse_error("unexpected-end-tag", {"name" => name})
593
599
  break
594
600
  end
595
601
  end