Skip to content

Commit 5f4c8f7

Browse files
authored
👌 IMPROVE: Add i18n support & general improvements (#66)
* Add i18n support and translations for togglebutton Introduces internationalization for Sphinx-ToggleButton by adding translation infrastructure, updating config values to use translated strings, and including translation files (.json, .po, .mo) for multiple languages. Updates MANIFEST.in to package translation assets and adjusts .gitignore to allow .mo files. Also adds a conversion script for generating locale files from JSON. * Include translation files in package data Added translation-related files and directories to the package_data section in setup.py to ensure they are included in the distribution. This supports proper packaging and deployment of translation resources. * Sync toggle button hints with external state changes Adds functions to synchronize toggle button hints and aria-expanded attributes with the current state. Introduces a MutationObserver to update button hints when toggle item classes change, ensuring external extensions or DOM changes are reflected in the UI. * Preserve existing IDs for admonition toggle items Update togglebutton.js to use an admonition's existing ID if present, instead of always generating a new one. This prevents overwriting custom or pre-existing IDs on admonition elements. * Refactor sphinx_togglebutton/__init__.py for readability Improved code formatting and structure for better readability and maintainability. Added blank lines for separation, split long function calls, and enhanced consistency in function definitions and configuration setup. * Refactor formatting in setup.py and _convert.py Improves code readability by reformatting lists and dictionary values in setup.py and breaking up a long path assignment in _convert.py. No functional changes were made. * Reorder imports for consistency and PEP8 compliance Imports in setup.py, __init__.py, and _convert.py were reordered to follow PEP8 guidelines and improve readability. No functional changes were made. * Refactor formatting and remove unused import Reformatted code for better readability in docs/conf.py and sphinx_togglebutton/__init__.py by expanding lists and function calls over multiple lines. Removed unused 'os' import from setup.py. * Add i18n support and document toggle button languages Updated CHANGELOG, README, and docs to document new internationalization support for toggle button texts. Added a list of supported languages and instructions for configuring language in Sphinx. Also mentioned new functions for dynamic hint updates and a fix for using existing admonition IDs. * Specify Sphinx configuration path in readthedocs.yml Added the 'sphinx.configuration' key to explicitly set the path to the Sphinx config file as 'docs/conf.py' for Read the Docs builds. * Update changelog with details on toggle hint functions Expanded the changelog entry for syncToggleHint and syncAllToggleHints to clarify that these functions allow automatic updating of button hint text when the open or closed state changes.
1 parent f301181 commit 5f4c8f7

File tree

76 files changed

+762
-17
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+762
-17
lines changed

‎.gitignore‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ coverage.xml
5252
.pytest_cache/
5353

5454
# Translations
55-
*.mo
55+
# *.mo
5656
*.pot
5757

5858
# Django stuff:

‎CHANGELOG.md‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Added
6+
7+
- Support for more languages in toggle button text (see README for full list) [#66](https://github.com/executablebooks/sphinx-togglebutton/pull/66).
8+
- Added new functions (syncToggleHint, syncAllToggleHints) to dynamically update toggle button hints based on the current state [#66](https://github.com/executablebooks/sphinx-togglebutton/pull/66). This allows developers to change the open or closed state of an element and have the button hint text update accordingly automatically.
9+
10+
### Fixed
11+
12+
- Update togglebutton.js to use an admonition's existing ID if present, instead of always generating a new one [#66](https://github.com/executablebooks/sphinx-togglebutton/pull/66).
13+
314
## v0.3.2 - 2022-07-15
415

516
([full changelog](https://github.com/executablebooks/sphinx-togglebutton/compare/v0.3.1...347b1ad3a093afad0f0d4c0041249f09f39afab2))

‎MANIFEST.in‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
11
graft doc/
2+
3+
recursive-include sphinx_togglebutton *.js
4+
recursive-include sphinx_togglebutton *.css
5+
6+
recursive-include sphinx_togglebutton *.json
7+
recursive-include sphinx_togglebutton *.mo
8+
recursive-include sphinx_togglebutton *.po
9+
recursive-include sphinx_togglebutton *.py

‎README.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,10 @@ here's a container with an image inside:
6969
7070
.. image:: https://media.giphy.com/media/mW05nwEyXLP0Y/giphy.gif
7171
```
72+
73+
Internationalization (i18n)
74+
============
75+
76+
The texts `Click to hide` and `Click to show` used in the toggle buttons are internationalized by using the set language from Sphinx's configuration.
77+
78+
Supported languages are English (default), Chinese (Simplified), Chinese (Traditional), Hindi, Spanish, French, Arabic, Bengali, Russian, Portuguese, Indonesian, Japanese, German, Korean, Turkish, Vietnamese, Tamil, Italian, Thai, Dutch, Greek, Polish, Ukrainian, Persian, Malay, Swahili, Romanian, Czech, Hungarian, Hebrew, Swedish, and Norwegian.

‎docs/conf.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@
1111

1212

1313
# -- General configuration ---------------------------------------------------
14-
extensions = ["myst_nb", "sphinx_examples", "sphinx_design", "sphinx_togglebutton"]
14+
extensions = [
15+
"myst_nb",
16+
"sphinx_examples",
17+
"sphinx_design",
18+
"sphinx_togglebutton",
19+
]
1520
templates_path = ["_templates"]
1621
source_suffix = ".rst"
1722
main_doc = "index"

‎docs/use.md‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,16 @@ Here is my toggle-able content!
129129
## Change the button hint text
130130

131131
You can control the "hint" text that is displayed next to togglebuttons.
132-
To do so, use the following configuration variable in your `conf.py` file:
132+
133+
To use the default values for your language, set the language in your Sphinx configuration:
134+
135+
```python
136+
language = "nl" # or "de", "es", etc.
137+
```
138+
139+
Supported languages are English (default), Chinese (Simplified), Chinese (Traditional), Hindi, Spanish, French, Arabic, Bengali, Russian, Portuguese, Indonesian, Japanese, German, Korean, Turkish, Vietnamese, Tamil, Italian, Thai, Dutch, Greek, Polish, Ukrainian, Persian, Malay, Swahili, Romanian, Czech, Hungarian, Hebrew, Swedish, and Norwegian.
140+
141+
If you prefer to have custom hint texts instead of the defaults for your language, use the following configuration variable in your `conf.py` file:
133142

134143
```python
135144
togglebutton_hint = "Displayed when the toggle is closed."

‎readthedocs.yml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
version: 2
2+
sphinx:
3+
# Path to your Sphinx configuration file.
4+
configuration: docs/conf.py
25
build:
36
os: "ubuntu-22.04"
47
tools:

‎setup.py‎

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import os
21
from pathlib import Path
3-
from setuptools import setup, find_packages
2+
3+
from setuptools import find_packages, setup
44

55
version = [
66
line
@@ -24,9 +24,26 @@
2424
license="MIT License",
2525
packages=find_packages(),
2626
package_data={
27-
"sphinx_togglebutton": ["_static/togglebutton.css", "_static/togglebutton.js", "_static/togglebutton-chevron.svg"]
27+
"sphinx_togglebutton": [
28+
"_static/togglebutton.css",
29+
"_static/togglebutton.js",
30+
"_static/togglebutton-chevron.svg",
31+
"translations/README.md",
32+
"translations/_convert.py",
33+
"translations/jsons/*.json",
34+
"translations/locales/**/*",
35+
]
2836
},
2937
install_requires=["setuptools", "wheel", "sphinx", "docutils"],
30-
extras_require={"sphinx": ["matplotlib", "numpy", "myst_nb", "sphinx_book_theme", "sphinx_design", "sphinx_examples"]},
38+
extras_require={
39+
"sphinx": [
40+
"matplotlib",
41+
"numpy",
42+
"myst_nb",
43+
"sphinx_book_theme",
44+
"sphinx_design",
45+
"sphinx_examples",
46+
]
47+
},
3148
classifiers=["License :: OSI Approved :: MIT License"],
3249
)

‎sphinx_togglebutton/__init__.py‎

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,44 @@
11
"""A small sphinx extension to add "toggle" buttons to items."""
2+
23
import os
3-
from docutils.parsers.rst import Directive, directives
4+
45
from docutils import nodes
6+
from docutils.parsers.rst import Directive, directives
7+
from sphinx.locale import get_translation
8+
9+
MESSAGE_CATALOG_NAME = "togglebutton"
10+
translate = get_translation(MESSAGE_CATALOG_NAME)
511

612
__version__ = "0.3.2"
713

814

915
def st_static_path(app):
10-
static_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "_static"))
16+
static_path = os.path.abspath(
17+
os.path.join(os.path.dirname(__file__), "_static")
18+
)
1119
app.config.html_static_path.append(static_path)
1220

1321

1422
def initialize_js_assets(app, config):
1523
# Update the global context
16-
app.add_js_file(None, body=f"let toggleHintShow = '{config.togglebutton_hint}';")
17-
app.add_js_file(None, body=f"let toggleHintHide = '{config.togglebutton_hint_hide}';")
24+
25+
app.add_js_file(
26+
None, body=f"let toggleHintShow = '{config.togglebutton_hint}';"
27+
)
28+
app.add_js_file(
29+
None, body=f"let toggleHintHide = '{config.togglebutton_hint_hide}';"
30+
)
1831
open_print = str(config.togglebutton_open_on_print).lower()
1932
app.add_js_file(None, body=f"let toggleOpenOnPrint = '{open_print}';")
2033
app.add_js_file("togglebutton.js")
2134

2235

2336
# This function reads in a variable and inserts it into JavaScript
37+
38+
2439
def insert_custom_selection_config(app):
2540
# This is a configuration that you've specified for users in `conf.py`
41+
2642
selector = app.config["togglebutton_selector"]
2743
js_text = "var togglebuttonSelector = '%s';" % selector
2844
app.add_js_file(None, body=js_text)
@@ -42,28 +58,45 @@ def run(self):
4258
classes = ["toggle"]
4359
if "show" in self.options:
4460
classes.append("toggle-shown")
45-
4661
parent = nodes.container(classes=classes)
4762
self.state.nested_parse(self.content, self.content_offset, parent)
4863
return [parent]
4964

5065

5166
# We connect this function to the step after the builder is initialized
67+
68+
5269
def setup(app):
70+
# add translations
71+
72+
package_dir = os.path.abspath(os.path.dirname(__file__))
73+
locale_dir = os.path.join(package_dir, "translations", "locales")
74+
app.add_message_catalog(MESSAGE_CATALOG_NAME, locale_dir)
75+
5376
# Add our static path
77+
5478
app.connect("builder-inited", st_static_path)
5579

5680
# Add relevant code to headers
81+
5782
app.add_css_file("togglebutton.css")
5883

5984
# Add the string we'll use to select items in the JS
6085
# Tell Sphinx about this configuration variable
61-
app.add_config_value("togglebutton_selector", ".toggle, .admonition.dropdown", "html")
62-
app.add_config_value("togglebutton_hint", "Click to show", "html")
63-
app.add_config_value("togglebutton_hint_hide", "Click to hide", "html")
86+
87+
app.add_config_value(
88+
"togglebutton_selector", ".toggle, .admonition.dropdown", "html"
89+
)
90+
app.add_config_value(
91+
"togglebutton_hint", f"{translate('Click to show')}", "html"
92+
)
93+
app.add_config_value(
94+
"togglebutton_hint_hide", f"{translate('Click to hide')}", "html"
95+
)
6496
app.add_config_value("togglebutton_open_on_print", True, "html")
6597

6698
# Run the function after the builder is initialized
99+
67100
app.connect("builder-inited", insert_custom_selection_config)
68101
app.connect("config-inited", initialize_js_assets)
69102
app.add_directive("toggle", Toggle)

‎sphinx_togglebutton/_static/togglebutton.js‎

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,13 @@ var initToggleItems = () => {
1717
itemsToToggle.forEach((item, index) => {
1818
if (item.classList.contains("admonition")) {
1919
// If it's an admonition block, then we'll add a button inside
20-
// Generate unique IDs for this item
21-
var toggleID = `toggle-${index}`;
20+
// Generate unique IDs for this item,
21+
// IF AND ONLY IF THE ITEM DOESN'T ALREADY HAVE AN ID
22+
if (!item.id) {
23+
var toggleID = `toggle-${index}`;
24+
} else {
25+
var toggleID = item.id;
26+
}
2227
var buttonID = `button-${toggleID}`;
2328

2429
item.setAttribute("id", toggleID);
@@ -123,6 +128,25 @@ var toggleHidden = (button) => {
123128
}
124129
};
125130

131+
// Function to synchronize the data-toggle-hint with the current state
132+
var syncToggleHint = (button) => {
133+
const target = button.dataset["target"];
134+
const itemToToggle = document.getElementById(target);
135+
136+
if (itemToToggle && itemToToggle.classList.contains("toggle-hidden")) {
137+
button.dataset.toggleHint = toggleHintShow;
138+
button.setAttribute("aria-expanded", false);
139+
} else if (itemToToggle) {
140+
button.dataset.toggleHint = toggleHintHide;
141+
button.setAttribute("aria-expanded", true);
142+
}
143+
};
144+
145+
// Function to sync all toggle buttons - can be called by external extensions
146+
var syncAllToggleHints = () => {
147+
document.querySelectorAll('.toggle-button').forEach(syncToggleHint);
148+
};
149+
126150
var toggleClickHandler = (click) => {
127151
// Be cause the admonition title is clickable and extends to the whole admonition
128152
// We only look for a click event on this title to trigger the toggle.
@@ -170,6 +194,33 @@ const sphinxToggleRunWhenDOMLoaded = (cb) => {
170194
sphinxToggleRunWhenDOMLoaded(addToggleToSelector);
171195
sphinxToggleRunWhenDOMLoaded(initToggleItems);
172196

197+
// Set up MutationObserver to watch for external changes to toggle states
198+
sphinxToggleRunWhenDOMLoaded(() => {
199+
const observer = new MutationObserver((mutations) => {
200+
mutations.forEach((mutation) => {
201+
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
202+
const target = mutation.target;
203+
// Check if this is a toggle item that had its class changed
204+
if (target.classList.contains('toggle')) {
205+
// Find the associated toggle button and sync its hint
206+
const button = target.querySelector('.toggle-button');
207+
if (button) {
208+
syncToggleHint(button);
209+
}
210+
}
211+
}
212+
});
213+
});
214+
215+
// Start observing class changes on all toggle elements
216+
document.querySelectorAll('.toggle').forEach((toggleElement) => {
217+
observer.observe(toggleElement, {
218+
attributes: true,
219+
attributeFilter: ['class']
220+
});
221+
});
222+
});
223+
173224
/** Toggle details blocks to be open when printing */
174225
if (toggleOpenOnPrint == "true") {
175226
window.addEventListener("beforeprint", () => {

0 commit comments

Comments
 (0)