Repository: sphinx-doc/sphinx

Issue:
Inconsistent smart quotes for zh_CN and zh_TW
### Describe the bug

docutils is unable to differentiate between opening and closing quotes in Chinese text, as words in Chinese are written without spaces too.

### How to Reproduce

`index.rst`  
```rst
我喜歡"書"和"音樂"。
```
`conf.py`
```py
language="zh_TW"
```
Build:
```bash
sphinx-build . build
```
`./build/index.html` contains:
```
我喜歡」書」和」音樂」。
```
#### Expected Output:
```
我喜歡「書」和「音樂」。
```
Similar procedure for language=`zh_CN`

### Environment Information

```text
Platform:              linux; (Linux-5.15.153.1-microsoft-standard-WSL2-x86_64-with-glibc2.39)
Python version:        3.12.3 (main, Jul 31 2024, 17:43:48) [GCC 13.2.0])
Python implementation: CPython
Sphinx version:        8.0.2
Docutils version:      0.21.2
Jinja2 version:        3.1.4
Pygments version:      2.18.0
```


### Sphinx extensions

_No response_

### Additional context

Relates to issue #4142.

### Solution
Disable default smartquotes behavior for zh_CN and zh_TW languages too.

Discussion:

Solution patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 3d5d3913326..1a7482024bf 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -17,6 +17,7 @@ Incompatible changes
   Code-blokcs are unchanged as FreeMono is now loaded with ``Scale=0.9``.
   An adjustement to existing projects is needed only if they used a custom
   :ref:`fontpkg` configuration and did not set :ref:`fvset`.
+* #12875: Disable smartquotes for languages: ``zh_CN`` and ``zh_TW`` by default.
 
 Deprecated
 ----------
diff --git a/sphinx/config.py b/sphinx/config.py
index bae92140d59..0fd2102e732 100644
--- a/sphinx/config.py
+++ b/sphinx/config.py
@@ -271,7 +271,7 @@ class Config:
         'smartquotes': _Opt(True, 'env', ()),
         'smartquotes_action': _Opt('qDe', 'env', ()),
         'smartquotes_excludes': _Opt(
-            {'languages': ['ja'], 'builders': ['man', 'text']}, 'env', ()),
+            {'languages': ['ja', 'zh_CN', 'zh_TW'], 'builders': ['man', 'text']}, 'env', ()),
         'option_emphasise_placeholders': _Opt(False, 'env', ()),
     }
 


Test patch:
diff --git a/tests/test_markup/test_smartquotes.py b/tests/test_markup/test_smartquotes.py
index e9ee9f3c7ac..b57a8a81017 100644
--- a/tests/test_markup/test_smartquotes.py
+++ b/tests/test_markup/test_smartquotes.py
@@ -86,6 +86,32 @@ def test_ja_html_builder(app):
     assert '<p>-- &quot;Sphinx&quot; is a tool that makes it easy ...</p>' in content
 
 
+@pytest.mark.sphinx(
+    'html',
+    testroot='smartquotes',
+    freshenv=True,
+    confoverrides={'language': 'zh_CN'},
+)
+def test_zh_cn_html_builder(app):
+    app.build()
+
+    content = (app.outdir / 'index.html').read_text(encoding='utf8')
+    assert '<p>-- &quot;Sphinx&quot; is a tool that makes it easy ...</p>' in content
+
+
+@pytest.mark.sphinx(
+    'html',
+    testroot='smartquotes',
+    freshenv=True,
+    confoverrides={'language': 'zh_TW'},
+)
+def test_zh_tw_html_builder(app):
+    app.build()
+
+    content = (app.outdir / 'index.html').read_text(encoding='utf8')
+    assert '<p>-- &quot;Sphinx&quot; is a tool that makes it easy ...</p>' in content
+
+
 @pytest.mark.sphinx(
     'html',
     testroot='smartquotes',