Automating Localized Quotation Marks with CSS Quotes

The CSS quotes property automates language-specific quotation marks by enabling browsers to substitute semantic quote tokens with culturally accurate typographical symbols based on the document's language settings. When combined with the semantic HTML <q> tag and the lang attribute, it eliminates the need to hardcode diverse punctuation styles into translated strings, streamlining the internationalization (i18n) process and ensuring consistent typography across multilingual websites.

The Mechanism of Semantic Quotation Marks

The HTML <q> element represents inline quotations. Rather than containing literal quote characters within the source code, standard user agent stylesheets generate quotation marks around <q> elements using pseudo-elements:

q::before {
  content: open-quote;
}
q::after {
  content: close-quote;
}

The values for open-quote and close-quote are determined by the CSS quotes property. This property accepts pairs of strings representing opening and closing marks, with support for nested levels of quotation.

The Localization Challenge

Punctuation rules differ significantly across languages and locales:

  • English (US): Uses double curved quotes (“ and ”) for outer quotes, and single quotes (‘ and ’) for inner quotes.
  • French: Uses guillemets with non-breaking spaces («\00A0 and \00A0»).
  • German: Uses low double quotes to open and high curved quotes to close („ and “).
  • Japanese: Uses corner brackets (「 and 」).

Hardcoding these characters directly into translation files often leads to inconsistent characters, improper spacing, and errors when content is repurposed across different regions.

Automated Language Selection via CSS

Modern browsers use the HTML lang attribute to automatically apply regional quotation styles. When the document root (<html lang="fr">) or a specific container (<div lang="de">) specifies a language, the browser applies its built-in typographical presets for that locale.

Developers can explicitly control and standardize these behaviors across all browsers using the CSS :lang() pseudo-class:

:lang(en) {
  quotes: "“" "”" "‘" "’";
}

:lang(fr) {
  quotes: "«\00A0" "\00A0»" "‹\00A0" "\00A0›";
}

:lang(de) {
  quotes: "„" "“" "‚" "‘";
}

Handling Nested Quotes Automatically

The quotes property accepts multiple pairs of strings to handle hierarchy. The first pair defines the outermost quotation, the second pair defines the first nested quotation, and subsequent pairs define deeper levels.

For instance, in the French rule:

quotes: "«\00A0" "\00A0»" "‹\00A0" "\00A0›";

A nested structure such as:

<p lang="fr">
  <q>Il a dit: <q>Bonjour</q> à tout le monde.</q>
</p>

Renders dynamically as: « Il a dit: ‹ Bonjour › à tout le monde. »

If the parent container's lang attribute is switched to en, the exact same HTML structure automatically updates to American English quotation standards without any alterations to the DOM or source text: “Il a dit: ‘Bonjour’ à tout le monde.”

Implementation Benefits in Localization

  1. Clean Source Data: Translators only translate the text itself, without having to insert locale-specific quote glyphs or manage HTML entities for non-breaking spaces.
  2. Global Maintenance: Punctuation rules can be updated, refined, or corrected sitewide through a single stylesheet declaration.
  3. Typography Standards: Web fonts often display certain quotation marks poorly; managing quotes in CSS allows teams to apply font-specific adjustments or alternate characters programmatically based on locale.