diff --git a/smartypants.php b/smartypants.php --- a/smartypants.php +++ b/smartypants.php @@ -11,6 +11,7 @@ * * Copyright (c) 2003-2004 John Gruber * Copyright (c) 2004-2005 Michel Fortin + * Copyright (c) 2011 Micha Glave - i18n-quote-style * * Re-released under GPLv2 for Drupal. */ @@ -23,7 +24,7 @@ // A global variable to keep track of our current SmartyPants // configuration setting. global $_typogrify_smartypants_attr; -$_typogrify_smartypants_attr = "1"; # Change this to configure. +$_typogrify_smartypants_attr = "1Q"; # Change this to configure. # 1 => "--" for em-dashes; no en-dash support # 2 => "---" for em-dashes; "--" for en-dashes # 3 => "--" for em-dashes; "---" for en-dashes @@ -35,6 +36,17 @@ return SmartyPants($text, $attr); } +function typogrify_i18n_quotes($langcode = NULL) { + $quotes = array( + 'de' => array( 'do' => '„', 'dc' => '“', 'so' => '‚', 'sc' => '‘',), + 'en' => array( 'do' => '“', 'dc' => '”', 'so' => '‘', 'sc' => '’',), + 'nl' => array( 'do' => '„', 'dc' => '“', 'so' => '‘', 'sc' => '’',), + 'ru' => array( 'do' => '«', 'dc' => '»', 'so' => '‘', 'sc' => '’',), + ); + if ($langcode == 'all') { return $quotes; } + if (isset($quotes[$langcode])) { return $quotes[$langcode]; } + return $quotes['en']; +} function SmartyPants($text, $attr = NULL, $ctx = NULL) { @@ -49,6 +61,7 @@ $do_stupefy = FALSE; $convert_quot = 0; # should we translate " entities into normal quotes? + # Parse attributes: # 0 : do nothing # 1 : set all @@ -56,8 +69,8 @@ # 3 : set all, using inverted old school en and em- dash shortcuts # # q : quotes - # b : backtick quotes (``double'' only) - # B : backtick quotes (``double'' and `single') + # b : backtick quotes (``double'' and ,,double`` only) + # B : backtick quotes (``double'', ,,double``, ,single` and `single') # d : dashes # D : old school dashes # i : inverted old school dashes @@ -70,21 +83,21 @@ } else if ($attr == "1") { # Do everything, turn all options on. - $do_quotes = 1; + $do_quotes = 2; $do_backticks = 1; $do_dashes = 1; $do_ellipses = 1; } else if ($attr == "2") { # Do everything, turn all options on, use old school dash shorthand. - $do_quotes = 1; + $do_quotes = 2; $do_backticks = 1; $do_dashes = 2; $do_ellipses = 1; } else if ($attr == "3") { # Do everything, turn all options on, use inverted old school dash shorthand. - $do_quotes = 1; + $do_quotes = 2; $do_backticks = 1; $do_dashes = 3; $do_ellipses = 1; @@ -97,7 +110,8 @@ $chars = preg_split('//', $attr); foreach ($chars as $c){ if ($c == "q") { $do_quotes = 1; } - else if ($c == "b") { $do_backticks = 1; } + else if ($c == "Q") { $do_quotes = 2; } + else if ($c == "b") { $do_backticks = 1; } else if ($c == "B") { $do_backticks = 2; } else if ($c == "d") { $do_dashes = 1; } else if ($c == "D") { $do_dashes = 2; } @@ -109,6 +123,9 @@ } } } + + if ($do_quotes == 2) { $quotes = typogrify_i18n_quotes($ctx['langcode']); } + else { $quotes = $typogrify_i18n_quotes('en'); } $tokens = _TokenizeHTML($text); $result = ''; @@ -151,32 +168,31 @@ $t = EducateBackticks($t); if ($do_backticks == 2) $t = EducateSingleBackticks($t); } - if ($do_quotes) { + $t = EducateBackticks($t); if ($t == "'") { # Special case: single-character ' token if (preg_match('/\S/', $prev_token_last_char)) { - $t = "’"; + $t = $quote['sc']; } else { - $t = "‘"; + $t = $quote['so']; } } else if ($t == '"') { # Special case: single-character " token if (preg_match('/\S/', $prev_token_last_char)) { - $t = "”"; + $t = $quote['dc']; } else { - $t = "“"; + $t = $quote['do']; } } else { # Normal case: - $t = EducateQuotes($t); + $t = EducateQuotes($t, $quotes); } } - if ($do_stupefy) $t = StupefyEntities($t); } $prev_token_last_char = $last_char; @@ -368,7 +384,7 @@ } -function EducateQuotes($_) { +function EducateQuotes($_, $quotes) { # # Parameter: String. # @@ -385,14 +401,14 @@ # followed by punctuation at a non-word-break. Close the quotes by brute force: $_ = preg_replace( array("/^'(?=$punct_class\\B)/", "/^\"(?=$punct_class\\B)/"), - array('’', '”'), $_); + array($quotes['sc'], $quotes['dc']), $_); # Special case for double sets of quotes, e.g.: #
He said, "'Quoted' words in a larger quote."
$_ = preg_replace( - array("/\"'(?=\w)/", "/'\"(?=\w)/"), - array('“‘', '‘“'), $_); + array("/\"'(?=\w)/", "/'\"(?=\w)/"), + array($quotes['do'].$quotes['so'], $quotes['so'].$quotes['do']), $_); # Special case for decade abbreviations (the '80s): $_ = preg_replace("/'(?=\\d{2}s)/", '’', $_); @@ -403,16 +419,16 @@ # Get most opening single quotes: $_ = preg_replace("{ ( - \\s | # a whitespace char, or + \\s | # a whitespace char, or | # a non-breaking space entity, or -- | # dashes, or &[mn]dash; | # named dash entities $dec_dashes | # or decimal entities - &\\#x201[34]; # or hex + &\\#x201[34]; # or hex ) ' # the quote - (?=\\w) # followed by a word character - }x", '\1‘', $_); + (?=\\w) # followed by a word character + }x", '\1'.$quotes['so'], $_); # Single closing quotes: $_ = preg_replace("{ ($close_class)? @@ -422,36 +438,36 @@ ) # char or an 's' at a word ending position. This # is a special case to handle something like: # \"Custer's Last Stand.\" - }xi", '\1’', $_); + }xi", '\1'.$quotes['sc'], $_); # Any remaining single quotes should be opening ones: - $_ = str_replace("'", '‘', $_); + $_ = str_replace("'", $quotes['so'], $_); # Get most opening double quotes: $_ = preg_replace("{ ( - \\s | # a whitespace char, or + \\s | # a whitespace char, or | # a non-breaking space entity, or -- | # dashes, or &[mn]dash; | # named dash entities $dec_dashes | # or decimal entities - &\\#x201[34]; # or hex + &\\#x201[34]; # or hex ) - \" # the quote - (?=\\w) # followed by a word character - }x", '\1“', $_); + \" # the quote + (?=\\w) # followed by a word character + }x", '\1'.$quotes['do'], $_); # Double closing quotes: $_ = preg_replace("{ ($close_class)? \" (?(1)|(?=\\s)) # If $1 captured, then do nothing; - # if not, then make sure the next char is whitespace. - }x", '\1”', $_); + # if not, then make sure the next char is whitespace. + }x", '\1'.$quotes['dc'], $_); # Any remaining quotes should be opening ones. - $_ = str_replace('"', '“', $_); + $_ = str_replace('"', $quotes['do'], $_); return $_; } @@ -467,8 +483,8 @@ # Example output: “Isn't this fun?” # - $_ = str_replace(array("``", "''",), - array('“', '”'), $_); + $_ = str_replace(array("``", "''", ",,"), + array('“', '”', '„'), $_); return $_; } @@ -483,8 +499,8 @@ # Example output: ‘Isn’t this fun?’ # - $_ = str_replace(array("`", "'",), - array('‘', '’'), $_); + $_ = str_replace(array("`", "'", ","), + array('‘', '’', '‚'), $_); return $_; } @@ -572,10 +588,10 @@ array('-', '--'), $_); # single quote open close - $_ = str_replace(array('‘', '’'), "'", $_); + $_ = str_replace(array('‘', '’','‚'), "'", $_); # double quote open close - $_ = str_replace(array('“', '”'), '"', $_); + $_ = str_replace(array('“', '”','„'), '"', $_); $_ = str_replace('…', '...', $_); # ellipsis @@ -598,10 +614,11 @@ # \. . # \- - # \` ` +# \, , # $_ = str_replace( - array('\\\\', '\"', "\'", '\.', '\-', '\`'), - array('\', '"', ''', '.', '-', '`'), $_); + array('\\\\', '\"', "\'", '\.', '\-', '\`', '\,', '<', '>',), + array('\', '"', ''', '.', '-', '`', ',', '<', '>',), $_); return $_; }