Quellcode durchsuchen

pass lang and custom_attrs from app to html root (#2697)

* pass lang and custom_attrs from app to html root

* fix some pre-commit errors and try adding lang

* fix tests

* really fix test

* cleanup with @benedikt-bartscher

* fix props and tests

* use str instead of var

* change typing of html_custom_attrs to not allow Vars
macmoritz vor 1 Jahr
Ursprung
Commit
9e0452beb0

+ 12 - 1
reflex/app.py

@@ -133,6 +133,12 @@ class App(Base):
     # Components to add to the head of every page.
     # Components to add to the head of every page.
     head_components: List[Component] = []
     head_components: List[Component] = []
 
 
+    # The language to add to the html root tag of every page.
+    html_lang: Optional[str] = None
+
+    # Attributes to add to the html root tag of every page.
+    html_custom_attrs: Optional[Dict[str, str]] = None
+
     # A component that is present on every page.
     # A component that is present on every page.
     overlay_component: Optional[
     overlay_component: Optional[
         Union[Component, ComponentCallable]
         Union[Component, ComponentCallable]
@@ -782,7 +788,12 @@ class App(Base):
             submit_work(compiler.compile_root_stylesheet, self.stylesheets)
             submit_work(compiler.compile_root_stylesheet, self.stylesheets)
 
 
             # Compile the root document.
             # Compile the root document.
-            submit_work(compiler.compile_document_root, self.head_components)
+            submit_work(
+                compiler.compile_document_root,
+                self.head_components,
+                html_lang=self.html_lang,
+                html_custom_attrs=self.html_custom_attrs,
+            )
 
 
             # Compile the theme.
             # Compile the theme.
             submit_work(compiler.compile_theme, style=self.style)
             submit_work(compiler.compile_theme, style=self.style)

+ 12 - 3
reflex/compiler/compiler.py

@@ -4,7 +4,7 @@ from __future__ import annotations
 
 
 import os
 import os
 from pathlib import Path
 from pathlib import Path
-from typing import Iterable, Optional, Type
+from typing import Dict, Iterable, Optional, Type, Union
 
 
 from reflex import constants
 from reflex import constants
 from reflex.compiler import templates, utils
 from reflex.compiler import templates, utils
@@ -19,6 +19,7 @@ from reflex.config import get_config
 from reflex.state import BaseState
 from reflex.state import BaseState
 from reflex.style import LIGHT_COLOR_MODE
 from reflex.style import LIGHT_COLOR_MODE
 from reflex.utils.imports import ImportVar
 from reflex.utils.imports import ImportVar
+from reflex.vars import Var
 
 
 
 
 def _compile_document_root(root: Component) -> str:
 def _compile_document_root(root: Component) -> str:
@@ -299,11 +300,17 @@ def _compile_tailwind(
     )
     )
 
 
 
 
-def compile_document_root(head_components: list[Component]) -> tuple[str, str]:
+def compile_document_root(
+    head_components: list[Component],
+    html_lang: Optional[str] = None,
+    html_custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
+) -> tuple[str, str]:
     """Compile the document root.
     """Compile the document root.
 
 
     Args:
     Args:
         head_components: The components to include in the head.
         head_components: The components to include in the head.
+        html_lang: The language of the document, will be added to the html root element.
+        html_custom_attrs: custom attributes added to the html root element.
 
 
     Returns:
     Returns:
         The path and code of the compiled document root.
         The path and code of the compiled document root.
@@ -312,7 +319,9 @@ def compile_document_root(head_components: list[Component]) -> tuple[str, str]:
     output_path = utils.get_page_path(constants.PageNames.DOCUMENT_ROOT)
     output_path = utils.get_page_path(constants.PageNames.DOCUMENT_ROOT)
 
 
     # Create the document root.
     # Create the document root.
-    document_root = utils.create_document_root(head_components)
+    document_root = utils.create_document_root(
+        head_components, html_lang=html_lang, html_custom_attrs=html_custom_attrs
+    )
 
 
     # Compile the document root.
     # Compile the document root.
     code = _compile_document_root(document_root)
     code = _compile_document_root(document_root)

+ 11 - 2
reflex/compiler/utils.py

@@ -2,7 +2,7 @@
 from __future__ import annotations
 from __future__ import annotations
 
 
 import os
 import os
-from typing import Any, Callable, Type
+from typing import Any, Callable, Dict, Optional, Type, Union
 from urllib.parse import urlparse
 from urllib.parse import urlparse
 
 
 from pydantic.fields import ModelField
 from pydantic.fields import ModelField
@@ -24,6 +24,7 @@ from reflex.components.component import Component, ComponentStyle, CustomCompone
 from reflex.state import BaseState, Cookie, LocalStorage
 from reflex.state import BaseState, Cookie, LocalStorage
 from reflex.style import Style
 from reflex.style import Style
 from reflex.utils import console, format, imports, path_ops
 from reflex.utils import console, format, imports, path_ops
+from reflex.vars import Var
 
 
 # To re-export this function.
 # To re-export this function.
 merge_imports = imports.merge_imports
 merge_imports = imports.merge_imports
@@ -261,11 +262,17 @@ def compile_custom_component(
     )
     )
 
 
 
 
-def create_document_root(head_components: list[Component] | None = None) -> Component:
+def create_document_root(
+    head_components: list[Component] | None = None,
+    html_lang: Optional[str] = None,
+    html_custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
+) -> Component:
     """Create the document root.
     """Create the document root.
 
 
     Args:
     Args:
         head_components: The components to add to the head.
         head_components: The components to add to the head.
+        html_lang: The language of the document, will be added to the html root element.
+        html_custom_attrs: custom attributes added to the html root element.
 
 
     Returns:
     Returns:
         The document root.
         The document root.
@@ -277,6 +284,8 @@ def create_document_root(head_components: list[Component] | None = None) -> Comp
             Main.create(),
             Main.create(),
             NextScript.create(),
             NextScript.create(),
         ),
         ),
+        lang=html_lang or "en",
+        custom_attrs=html_custom_attrs or {},
     )
     )
 
 
 
 

+ 4 - 0
reflex/components/base/document.py

@@ -1,5 +1,7 @@
 """Document components."""
 """Document components."""
 
 
+from typing import Optional
+
 from reflex.components.component import Component
 from reflex.components.component import Component
 
 
 
 
@@ -14,6 +16,8 @@ class Html(NextDocumentLib):
 
 
     tag = "Html"
     tag = "Html"
 
 
+    lang: Optional[str]
+
 
 
 class DocumentHead(NextDocumentLib):
 class DocumentHead(NextDocumentLib):
     """The document head."""
     """The document head."""

+ 2 - 0
reflex/components/base/document.pyi

@@ -7,6 +7,7 @@ from typing import Any, Dict, Literal, Optional, Union, overload
 from reflex.vars import Var, BaseVar, ComputedVar
 from reflex.vars import Var, BaseVar, ComputedVar
 from reflex.event import EventChain, EventHandler, EventSpec
 from reflex.event import EventChain, EventHandler, EventSpec
 from reflex.style import Style
 from reflex.style import Style
+from typing import Optional
 from reflex.components.component import Component
 from reflex.components.component import Component
 
 
 class NextDocumentLib(Component):
 class NextDocumentLib(Component):
@@ -94,6 +95,7 @@ class Html(NextDocumentLib):
     def create(  # type: ignore
     def create(  # type: ignore
         cls,
         cls,
         *children,
         *children,
+        lang: Optional[str] = None,
         style: Optional[Style] = None,
         style: Optional[Style] = None,
         key: Optional[Any] = None,
         key: Optional[Any] = None,
         id: Optional[Any] = None,
         id: Optional[Any] = None,

+ 8 - 1
tests/compiler/test_compiler.py

@@ -195,8 +195,11 @@ def test_create_document_root():
     """Test that the document root is created correctly."""
     """Test that the document root is created correctly."""
     # Test with no components.
     # Test with no components.
     root = utils.create_document_root()
     root = utils.create_document_root()
+    root.render()
     assert isinstance(root, utils.Html)
     assert isinstance(root, utils.Html)
     assert isinstance(root.children[0], utils.DocumentHead)
     assert isinstance(root.children[0], utils.DocumentHead)
+    # Default language.
+    assert root.lang == "en"  # type: ignore
     # No children in head.
     # No children in head.
     assert len(root.children[0].children) == 0
     assert len(root.children[0].children) == 0
 
 
@@ -205,6 +208,10 @@ def test_create_document_root():
         utils.NextScript.create(src="foo.js"),
         utils.NextScript.create(src="foo.js"),
         utils.NextScript.create(src="bar.js"),
         utils.NextScript.create(src="bar.js"),
     ]
     ]
-    root = utils.create_document_root(head_components=comps)  # type: ignore
+    root = utils.create_document_root(head_components=comps, html_lang="rx", html_custom_attrs={"project": "reflex"})  # type: ignore
     # Two children in head.
     # Two children in head.
+    assert isinstance(root, utils.Html)
     assert len(root.children[0].children) == 2
     assert len(root.children[0].children) == 2
+    assert root.lang == "rx"  # type: ignore
+    assert isinstance(root.custom_attrs, dict)
+    assert root.custom_attrs == {"project": "reflex"}