1#!/usr/bin/perl 2# -*- cperl-indent-level: 8; -*- 3use warnings; 4use strict; 5use File::Temp qw{tempdir}; 6use utf8; 7 8BEGIN { 9 unless (eval { require Locale::Po4a::Chooser }) { 10 eval q{ 11 use Test::More skip_all => "Locale::Po4a::Chooser::new is not available" 12 } 13 } 14 unless (eval { require Locale::Po4a::Po }) { 15 eval q{ 16 use Test::More skip_all => "Locale::Po4a::Po::new is not available" 17 } 18 } 19} 20 21use Test::More; 22 23BEGIN { use_ok("IkiWiki"); } 24 25my $msgprefix; 26 27my $dir = tempdir("ikiwiki-test-po.XXXXXXXXXX", 28 DIR => File::Spec->tmpdir, 29 CLEANUP => 1); 30 31### Init 32%config=IkiWiki::defaultconfig(); 33$config{srcdir} = "$dir/src"; 34$config{destdir} = "$dir/dst"; 35$config{destdir} = "$dir/dst"; 36$config{underlaydirbase} = "/dev/null"; 37$config{underlaydir} = "/dev/null"; 38$config{url} = "http://example.com"; 39$config{cgiurl} = "http://example.com/ikiwiki.cgi"; 40$config{discussion} = 0; 41$config{po_master_language} = { code => 'en', 42 name => 'English' 43 }; 44$config{po_slave_languages} = { 45 es => 'Castellano', 46 fr => "Français" 47 }; 48$config{po_translatable_pages}='index or test1 or test2 or translatable or debian*'; 49$config{po_link_to}='negotiated'; 50IkiWiki::loadplugins(); 51ok(IkiWiki::loadplugin('meta'), "meta plugin loaded"); 52ok(IkiWiki::loadplugin('po'), "po plugin loaded"); 53IkiWiki::checkconfig(); 54 55### seed %pagesources and %pagecase 56$pagesources{'index'}='index.mdwn'; 57$pagesources{'index.fr'}='index.fr.po'; 58$pagesources{'index.es'}='index.es.po'; 59$pagesources{'test1'}='test1.mdwn'; 60$pagesources{'test1.es'}='test1.es.po'; 61$pagesources{'test1.fr'}='test1.fr.po'; 62$pagesources{'test2'}='test2.mdwn'; 63$pagesources{'test2.es'}='test2.es.po'; 64$pagesources{'test2.fr'}='test2.fr.po'; 65$pagesources{'test3'}='test3.mdwn'; 66$pagesources{'test3.es'}='test3.es.mdwn'; 67$pagesources{'translatable'}='translatable.mdwn'; 68$pagesources{'translatable.fr'}='translatable.fr.po'; 69$pagesources{'translatable.es'}='translatable.es.po'; 70$pagesources{'nontranslatable'}='nontranslatable.mdwn'; 71$pagesources{'debian911356'}='debian911356.mdwn'; 72$pagesources{'debian911356ish'}='debian911356ish.mdwn'; 73$pagesources{'debian911356.fr'}='debian911356.fr.po'; 74$pagesources{'debian911356ish.fr'}='debian911356ish.fr.po'; 75$pagesources{'debian911356-inlined'}='debian911356-inlined.mdwn'; 76$pagesources{'debian911356-inlined.fr'}='debian911356-inlined.fr.po'; 77$pagesources{'templates/feedlink.tmpl'}='templates/feedlink.tmpl'; 78$pagesources{'templates/inlinepage.tmpl'}='templates/inlinepage.tmpl'; 79my $now=time; 80foreach my $page (keys %pagesources) { 81 $IkiWiki::pagecase{lc $page}=$page; 82 $IkiWiki::pagectime{$page}=$now; 83 $IkiWiki::pagemtime{$page}=$now; 84} 85 86### populate srcdir 87writefile('index.mdwn', $config{srcdir}, 88 "[[!meta title=\"index title\"]]\n[[translatable]] [[nontranslatable]]"); 89writefile('test1.mdwn', $config{srcdir}, 90 "[[!meta title=\"test1 title\"]]\ntest1 content"); 91writefile('test2.mdwn', $config{srcdir}, 'test2 content'); 92writefile('test3.mdwn', $config{srcdir}, 'test3 content'); 93writefile('translatable.mdwn', $config{srcdir}, '[[nontranslatable]]'); 94writefile('nontranslatable.mdwn', $config{srcdir}, '[[/]] [[translatable]]'); 95writefile('debian911356.mdwn', $config{srcdir}, <<EOF); 96Before first inline 97 98[[!inline pages="debian911356-inlined" raw="yes"]] 99 100Between inlines 101 102[[!inline pages="debian911356-inlined" raw="yes"]] 103 104After inlines 105EOF 106writefile('debian911356-inlined.mdwn', $config{srcdir}, <<EOF); 107English content 108EOF 109writefile('debian911356.fr.po', $config{srcdir}, <<EOF); 110msgid "" msgstr "" 111"MIME-Version: 1.0\\n" 112"Content-Type: text/plain; charset=UTF-8\\n" 113"Content-Transfer-Encoding: 8bit\\n" 114 115msgid "Before first inline" 116msgstr "Avant la première inline" 117 118msgid "[[!inline pages=\\"debian911356-inlined\\" raw=\\"yes\\"]]\\n" 119msgstr "[[!inline pages=\\"debian911356-inlined.fr\\" raw=\\"yes\\"]]\\n" 120 121msgid "Between inlines" 122msgstr "Entre les inlines" 123 124msgid "After inlines" 125msgstr "Après les inlines" 126EOF 127writefile('debian911356-inlined.fr.po', $config{srcdir}, <<EOF); 128msgid "English content" 129msgstr "Contenu français" 130EOF 131writefile('debian911356ish.mdwn', $config{srcdir}, <<EOF); 132Before first inline 133 134[[!inline pages="debian911356-inlined"]] 135 136Between inlines 137 138[[!inline pages="debian911356-inlined"]] 139 140After inlines 141EOF 142writefile('debian911356ish.fr.po', $config{srcdir}, <<EOF); 143msgid "" msgstr "" 144"MIME-Version: 1.0\\n" 145"Content-Type: text/plain; charset=UTF-8\\n" 146"Content-Transfer-Encoding: 8bit\\n" 147 148msgid "Before first inline" 149msgstr "Avant la première inline" 150 151msgid "[[!inline pages=\\"debian911356-inlined\\"]]\\n" 152msgstr "[[!inline pages=\\"debian911356-inlined.fr\\"]]\\n" 153 154msgid "Between inlines" 155msgstr "Entre les inlines" 156 157msgid "After inlines" 158msgstr "Après les inlines" 159EOF 160# We don't actually care what the feed links look like, so skip them 161writefile('templates/feedlink.tmpl', $config{srcdir}, <<EOF); 162<!--feedlinks--> 163EOF 164# Make inlines' appearance predictable so we can screen-scrape them 165writefile('templates/inlinepage.tmpl', $config{srcdir}, <<EOF); 166<div class="inlinecontent"> 167<h6><TMPL_VAR TITLE></h6> 168<TMPL_VAR CONTENT> 169</div><!--inlinecontent--> 170EOF 171 172### istranslatable/istranslation 173# we run these tests twice because memoization attempts made them 174# succeed once every two tries... 175foreach (1, 2) { 176ok(IkiWiki::Plugin::po::istranslatable('index'), "index is translatable"); 177ok(IkiWiki::Plugin::po::istranslatable('/index'), "/index is translatable"); 178ok(! IkiWiki::Plugin::po::istranslatable('index.fr'), "index.fr is not translatable"); 179ok(! IkiWiki::Plugin::po::istranslatable('index.es'), "index.es is not translatable"); 180ok(! IkiWiki::Plugin::po::istranslatable('/index.fr'), "/index.fr is not translatable"); 181ok(! IkiWiki::Plugin::po::istranslation('index'), "index is not a translation"); 182ok(IkiWiki::Plugin::po::istranslation('index.fr'), "index.fr is a translation"); 183ok(IkiWiki::Plugin::po::istranslation('index.es'), "index.es is a translation"); 184ok(IkiWiki::Plugin::po::istranslation('/index.fr'), "/index.fr is a translation"); 185ok(IkiWiki::Plugin::po::istranslatable('test1'), "test1 is translatable"); 186ok(IkiWiki::Plugin::po::istranslation('test1.es'), "test1.es is a translation"); 187ok(IkiWiki::Plugin::po::istranslation('test1.fr'), "test1.fr is a translation"); 188ok(IkiWiki::Plugin::po::istranslatable('test2'), "test2 is translatable"); 189ok(! IkiWiki::Plugin::po::istranslation('test2'), "test2 is not a translation"); 190ok(! IkiWiki::Plugin::po::istranslatable('test3'), "test3 is not translatable"); 191ok(! IkiWiki::Plugin::po::istranslation('test3'), "test3 is not a translation"); 192} 193 194### pofiles 195 196my @pofiles = IkiWiki::Plugin::po::pofiles(srcfile("index.mdwn")); 197ok( @pofiles, "pofiles is defined"); 198ok( @pofiles == 2, "pofiles has correct size"); 199is_deeply(\@pofiles, ["$config{srcdir}/index.es.po", "$config{srcdir}/index.fr.po"], "pofiles content is correct"); 200 201### links 202require IkiWiki::Render; 203 204sub refresh_n_scan(@) { 205 my @masterfiles_rel=@_; 206 foreach my $masterfile_rel (@masterfiles_rel) { 207 my $masterfile=srcfile($masterfile_rel); 208 IkiWiki::scan($masterfile_rel); 209 next unless IkiWiki::Plugin::po::istranslatable(pagename($masterfile_rel)); 210 my @pofiles=IkiWiki::Plugin::po::pofiles($masterfile); 211 IkiWiki::Plugin::po::refreshpot($masterfile); 212 IkiWiki::Plugin::po::refreshpofiles($masterfile, @pofiles); 213 map IkiWiki::scan(IkiWiki::abs2rel($_, $config{srcdir})), @pofiles; 214 } 215} 216 217$config{po_link_to}='negotiated'; 218$msgprefix="links (po_link_to=negotiated)"; 219refresh_n_scan('index.mdwn', 'translatable.mdwn', 'nontranslatable.mdwn'); 220is_deeply(\@{$links{'index'}}, ['translatable', 'nontranslatable'], "$msgprefix index"); 221is_deeply(\@{$links{'index.es'}}, ['translatable.es', 'nontranslatable'], "$msgprefix index.es"); 222is_deeply(\@{$links{'index.fr'}}, ['translatable.fr', 'nontranslatable'], "$msgprefix index.fr"); 223is_deeply(\@{$links{'translatable'}}, ['nontranslatable'], "$msgprefix translatable"); 224is_deeply(\@{$links{'translatable.es'}}, ['nontranslatable'], "$msgprefix translatable.es"); 225is_deeply(\@{$links{'translatable.fr'}}, ['nontranslatable'], "$msgprefix translatable.fr"); 226is_deeply([sort @{$links{'nontranslatable'}}], [sort('/', 'translatable', 'translatable.fr', 'translatable.es')], "$msgprefix nontranslatable"); 227 228$config{po_link_to}='current'; 229$msgprefix="links (po_link_to=current)"; 230refresh_n_scan('index.mdwn', 'translatable.mdwn', 'nontranslatable.mdwn'); 231is_deeply(\@{$links{'index'}}, ['translatable', 'nontranslatable'], "$msgprefix index"); 232is_deeply(\@{$links{'index.es'}}, [ (map bestlink('index.es', $_), ('translatable.es', 'nontranslatable'))], "$msgprefix index.es"); 233is_deeply(\@{$links{'index.fr'}}, [ (map bestlink('index.fr', $_), ('translatable.fr', 'nontranslatable'))], "$msgprefix index.fr"); 234is_deeply(\@{$links{'translatable'}}, [bestlink('translatable', 'nontranslatable')], "$msgprefix translatable"); 235is_deeply(\@{$links{'translatable.es'}}, ['nontranslatable'], "$msgprefix translatable.es"); 236is_deeply(\@{$links{'translatable.fr'}}, ['nontranslatable'], "$msgprefix translatable.fr"); 237is_deeply([sort @{$links{'nontranslatable'}}], [sort('/', 'translatable', 'translatable.fr', 'translatable.es')], "$msgprefix nontranslatable"); 238 239### targetpage 240$config{usedirs}=0; 241$msgprefix="targetpage (usedirs=0)"; 242is(targetpage('test1', 'html'), 'test1.en.html', "$msgprefix test1"); 243is(targetpage('test1.fr', 'html'), 'test1.fr.html', "$msgprefix test1.fr"); 244$config{usedirs}=1; 245$msgprefix="targetpage (usedirs=1)"; 246is(targetpage('index', 'html'), 'index.en.html', "$msgprefix index"); 247is(targetpage('index.fr', 'html'), 'index.fr.html', "$msgprefix index.fr"); 248is(targetpage('test1', 'html'), 'test1/index.en.html', "$msgprefix test1"); 249is(targetpage('test1.fr', 'html'), 'test1/index.fr.html', "$msgprefix test1.fr"); 250is(targetpage('test3', 'html'), 'test3/index.html', "$msgprefix test3 (non-translatable page)"); 251is(targetpage('test3.es', 'html'), 'test3.es/index.html', "$msgprefix test3.es (non-translatable page)"); 252 253### urlto -> index 254$config{po_link_to}='current'; 255$msgprefix="urlto (po_link_to=current)"; 256is(urlto('', 'index'), './index.en.html', "$msgprefix index -> ''"); 257is(urlto('', 'nontranslatable'), '../index.en.html', "$msgprefix nontranslatable -> ''"); 258is(urlto('', 'translatable.fr'), '../index.fr.html', "$msgprefix translatable.fr -> ''"); 259# when asking for a semi-absolute or absolute URL, we can't know what the 260# current language is, so for translatable pages we use the master language 261is(urlto('nontranslatable'), '/nontranslatable/', "$msgprefix 1-arg -> nontranslatable"); 262is(urlto('translatable'), '/translatable/index.en.html', "$msgprefix 1-arg -> translatable"); 263is(urlto('nontranslatable', undef, 1), 'http://example.com/nontranslatable/', "$msgprefix 1-arg -> nontranslatable"); 264is(urlto('index', undef, 1), 'http://example.com/index.en.html', "$msgprefix 1-arg -> index"); 265is(urlto('', undef, 1), 'http://example.com/index.en.html', "$msgprefix 1-arg -> ''"); 266# FIXME: should these three produce the negotiatable URL instead of the master 267# language? 268is(urlto(''), '/index.en.html', "$msgprefix 1-arg -> ''"); 269is(urlto('index'), '/index.en.html', "$msgprefix 1-arg -> index"); 270is(urlto('translatable', undef, 1), 'http://example.com/translatable/index.en.html', "$msgprefix 1-arg -> translatable"); 271 272$config{po_link_to}='negotiated'; 273$msgprefix="urlto (po_link_to=negotiated)"; 274is(urlto('', 'index'), './', "$msgprefix index -> ''"); 275is(urlto('', 'nontranslatable'), '../', "$msgprefix nontranslatable -> ''"); 276is(urlto('', 'translatable.fr'), '../', "$msgprefix translatable.fr -> ''"); 277is(urlto('nontranslatable'), '/nontranslatable/', "$msgprefix 1-arg -> nontranslatable"); 278is(urlto('translatable'), '/translatable/', "$msgprefix 1-arg -> translatable"); 279is(urlto(''), '/', "$msgprefix 1-arg -> ''"); 280is(urlto('index'), '/', "$msgprefix 1-arg -> index"); 281is(urlto('nontranslatable', undef, 1), 'http://example.com/nontranslatable/', "$msgprefix 1-arg -> nontranslatable"); 282is(urlto('translatable', undef, 1), 'http://example.com/translatable/', "$msgprefix 1-arg -> translatable"); 283is(urlto('index', undef, 1), 'http://example.com/', "$msgprefix 1-arg -> index"); 284is(urlto('', undef, 1), 'http://example.com/', "$msgprefix 1-arg -> ''"); 285 286### bestlink 287$config{po_link_to}='current'; 288$msgprefix="bestlink (po_link_to=current)"; 289is(bestlink('test1.fr', 'test2'), 'test2.fr', "$msgprefix test1.fr -> test2"); 290is(bestlink('test1.fr', 'test2.es'), 'test2.es', "$msgprefix test1.fr -> test2.es"); 291$config{po_link_to}='negotiated'; 292$msgprefix="bestlink (po_link_to=negotiated)"; 293is(bestlink('test1.fr', 'test2'), 'test2.fr', "$msgprefix test1.fr -> test2"); 294is(bestlink('test1.fr', 'test2.es'), 'test2.es', "$msgprefix test1.fr -> test2.es"); 295 296### beautify_urlpath 297$config{po_link_to}='default'; 298$msgprefix="beautify_urlpath (po_link_to=default)"; 299is(IkiWiki::beautify_urlpath('test1/index.en.html'), './test1/index.en.html', "$msgprefix test1/index.en.html"); 300is(IkiWiki::beautify_urlpath('test1/index.fr.html'), './test1/index.fr.html', "$msgprefix test1/index.fr.html"); 301$config{po_link_to}='negotiated'; 302$msgprefix="beautify_urlpath (po_link_to=negotiated)"; 303is(IkiWiki::beautify_urlpath('test1/index.html'), './test1/', "$msgprefix test1/index.html"); 304is(IkiWiki::beautify_urlpath('test1/index.en.html'), './test1/', "$msgprefix test1/index.en.html"); 305is(IkiWiki::beautify_urlpath('test1/index.fr.html'), './test1/', "$msgprefix test1/index.fr.html"); 306$config{po_link_to}='current'; 307$msgprefix="beautify_urlpath (po_link_to=current)"; 308is(IkiWiki::beautify_urlpath('test1/index.en.html'), './test1/index.en.html', "$msgprefix test1/index.en.html"); 309is(IkiWiki::beautify_urlpath('test1/index.fr.html'), './test1/index.fr.html', "$msgprefix test1/index.fr.html"); 310 311### re-scan 312refresh_n_scan('index.mdwn'); 313is($pagestate{'index'}{meta}{title}, 'index title'); 314is($pagestate{'index.es'}{meta}{title}, 'index title'); 315is($pagestate{'index.fr'}{meta}{title}, 'index title'); 316refresh_n_scan('test1.mdwn'); 317is($pagestate{'test1'}{meta}{title}, 'test1 title'); 318is($pagestate{'test1.es'}{meta}{title}, 'test1 title'); 319is($pagestate{'test1.fr'}{meta}{title}, 'test1 title'); 320 321### istranslatedto 322ok(IkiWiki::Plugin::po::istranslatedto('index', 'es')); 323ok(IkiWiki::Plugin::po::istranslatedto('index', 'fr')); 324ok(! IkiWiki::Plugin::po::istranslatedto('index', 'cz')); 325ok(IkiWiki::Plugin::po::istranslatedto('test1', 'es')); 326ok(IkiWiki::Plugin::po::istranslatedto('test1', 'fr')); 327ok(! IkiWiki::Plugin::po::istranslatedto('test1', 'cz')); 328ok(! IkiWiki::Plugin::po::istranslatedto('nontranslatable', 'es')); 329ok(! IkiWiki::Plugin::po::istranslatedto('nontranslatable', 'cz')); 330ok(! IkiWiki::Plugin::po::istranslatedto('test1.es', 'fr')); 331ok(! IkiWiki::Plugin::po::istranslatedto('test1.fr', 'es')); 332 333### islanguagecode 334ok(IkiWiki::Plugin::po::islanguagecode('en')); 335ok(IkiWiki::Plugin::po::islanguagecode('es')); 336ok(IkiWiki::Plugin::po::islanguagecode('arn')); 337ok(! IkiWiki::Plugin::po::islanguagecode('es_')); 338ok(! IkiWiki::Plugin::po::islanguagecode('_en')); 339 340# Actually render translated pages 341use IkiWiki::Render; 342 343my %output; 344foreach my $page (sort keys %pagesources) { 345 my $source = "$config{srcdir}/$pagesources{$page}"; 346 if (-e $source) { 347 IkiWiki::scan($pagesources{$page}); 348 } 349} 350 351# This is the most complicated case, so use this while we test rendering 352$config{po_link_to}='current'; 353 354foreach my $page (sort keys %pagesources) { 355 my $source = "$config{srcdir}/$pagesources{$page}"; 356 if (-e $source && defined IkiWiki::pagetype($pagesources{$page})) { 357 IkiWiki::scan($pagesources{$page}); 358 my $content = readfile($source); 359 #print STDERR "-------------------------------------\n"; 360 #print STDERR "SOURCE: $page: $content\n"; 361 $content = IkiWiki::filter($page, $page, $content); 362 #print STDERR "FILTERED: $page: $content\n"; 363 $content = IkiWiki::preprocess($page, $page, $content); 364 #print STDERR "PREPROCESSED: $page: $content\n"; 365 $content = IkiWiki::linkify($page, $page, $content); 366 #print STDERR "LINKIFIED: $page: $content\n"; 367 $content = IkiWiki::htmlize($page, $page, IkiWiki::pagetype($pagesources{$page}), $content); 368 #print STDERR "HTMLIZED: $page: $content\n"; 369 IkiWiki::run_hooks(format => sub { 370 $content=shift->( 371 page => $page, 372 content => $content, 373 ); 374 }); 375 #print STDERR "FORMATTED: $page: $content\n"; 376 $output{$page} = $content; 377 } 378} 379 380like($output{index}, qr{ 381 <p> 382 <a\s+href="\./translatable/index\.en\.html"> 383 translatable 384 </a>\s* 385 <a\s+href="\./nontranslatable/"> 386 nontranslatable 387 </a> 388 </p> 389}sx); 390 391like($output{'index.es'}, qr{ 392 <p> 393 <a\s+href="\./translatable/index\.es\.html"> 394 translatable 395 </a>\s* 396 <a\s+href="\./nontranslatable/"> 397 nontranslatable 398 </a> 399 </p> 400}sx); 401 402like($output{'index.fr'}, qr{ 403 <p> 404 <a\s+href="\./translatable/index\.fr\.html"> 405 translatable 406 </a>\s* 407 <a\s+href="\./nontranslatable/"> 408 nontranslatable 409 </a> 410 </p> 411}sx); 412 413like($output{'translatable'}, qr{ 414 <a\s+href="\.\./nontranslatable/"> 415 nontranslatable 416 </a> 417}sx); 418 419TODO: { 420local $TODO = 'was [[/]] meant to be a link to the index?'; 421unlike($output{'nontranslatable'}, qr{ 422 class=.createlink. 423}sx); 424}; 425like($output{'nontranslatable'}, qr{ 426 <a\s+href="\.\./translatable/index\.en\.html"> 427 translatable 428 </a> 429}sx); 430 431like($output{debian911356}, qr{ 432 <p>Before\sfirst\sinline</p> 433 \s* 434 <p>English\scontent</p> 435 \s* 436 <p>Between\sinlines</p> 437 \s* 438 <p>English\scontent</p> 439 \s* 440 <p>After\sinlines</p> 441}sx); 442 443like($output{'debian911356.fr'}, qr{ 444 <p>Avant\sla\spremière\sinline</p> 445 \s* 446 <p>Contenu\sfrançais</p> 447 \s* 448 <p>Entre\sles\sinlines</p> 449 \s* 450 <p>Contenu\sfrançais</p> 451 \s* 452 <p>Après\sles\sinlines</p> 453}sx); 454 455# Variation of Debian #911356 without using raw inlines. 456like($output{debian911356ish}, qr{ 457 <p>Before\sfirst\sinline</p> 458 \s* 459 <!--feedlinks--> 460 \s* 461 <div\sclass="inlinecontent"> 462 \s* 463 <h6>debian911356-inlined</h6> 464 \s* 465 <p>English\scontent</p> 466 \s* 467 </div><!--inlinecontent--> 468 \s* 469 <p>Between\sinlines</p> 470 \s* 471 <!--feedlinks--> 472 \s* 473 <div\sclass="inlinecontent"> 474 \s* 475 <h6>debian911356-inlined</h6> 476 \s* 477 <p>English\scontent</p> 478 \s* 479 </div><!--inlinecontent--> 480 \s* 481 <p>After\sinlines</p> 482}sx); 483 484like($output{'debian911356ish.fr'}, qr{ 485 <p>Avant\sla\spremière\sinline</p> 486 \s* 487 <!--feedlinks--> 488 \s* 489 <div\sclass="inlinecontent"> 490 \s* 491 <h6>debian911356-inlined\.fr</h6> 492 \s* 493 <p>Contenu\sfrançais</p> 494 \s* 495 </div><!--inlinecontent--> 496 \s* 497 <p>Entre\sles\sinlines</p> 498 \s* 499 <!--feedlinks--> 500 \s* 501 <div\sclass="inlinecontent"> 502 \s* 503 <h6>debian911356-inlined\.fr</h6> 504 \s* 505 <p>Contenu\sfrançais</p> 506 \s* 507 </div><!--inlinecontent--> 508 \s* 509 <p>Après\sles\sinlines</p> 510}sx); 511 512done_testing; 513