diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 13ff5425..0d94cb1f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -74,9 +74,9 @@ jobs:
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ matrix.browser }}-${{ hashFiles('**/Cargo.toml') }}-${{ hashFiles('**/Cargo.lock') }}
- - name: Run tests
+ - name: Run end to end tests
run: |
- cd tests
+ cd end2end
wasm-pack test --headless --${{ matrix.browser }}
build-example:
@@ -85,15 +85,11 @@ jobs:
strategy:
fail-fast: false
matrix:
- include:
- - example: csr-minimal
- feature: csr
- - example: csr-complete
- feature: csr
- - example: ssr-hydrate-actix
- feature: ssr
- - example: ssr-hydrate-axum
- feature: ssr
+ example:
+ - csr-minimal
+ - csr-complete
+ - ssr-hydrate-actix
+ - ssr-hydrate-axum
steps:
- uses: actions/checkout@v4
- name: Setup Rust
@@ -106,12 +102,12 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install trunk
- if: ${{ contains(matrix.feature, 'csr') }}
+ if: ${{ startsWith(matrix.example, 'csr') }}
run: cargo binstall -y trunk
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install cargo-leptos
- if: ${{ matrix.feature == 'ssr' }}
+ if: ${{ startsWith(matrix.example, 'ssr') }}
run: cargo binstall -y cargo-leptos
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -122,14 +118,14 @@ jobs:
~/.cargo/registry
~/.cargo/git
target
- key: ${{ runner.os }}-cargo-${{ matrix.example }}-${{ matrix.feature }}-${{ hashFiles('**/Cargo.toml') }}-${{ hashFiles('**/Cargo.lock') }}
+ key: ${{ runner.os }}-cargo-${{ matrix.example }}-${{ hashFiles('**/Cargo.toml') }}-${{ hashFiles('**/Cargo.lock') }}
- name: Build with trunk
- if: ${{ matrix.feature == 'csr' }}
+ if: ${{ startsWith(matrix.example, 'csr') }}
run: |
cd examples/${{ matrix.example }}
trunk build --release
- name: Build with cargo-leptos
- if: ${{ matrix.feature == 'ssr' }}
+ if: ${{ startsWith(matrix.example, 'ssr') }}
run: |
cd examples/${{ matrix.example }}
cargo leptos build --release
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b532abe7..02ec4946 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,26 @@
# CHANGELOG
+## 2024-05-20 - [0.0.24]
+
+### Enhancements
+
+- Add `I18n.is_active_language` method.
+- Add `I18n.language_key` method to return a hash for the current
+ language with their active status for usage in `For` components.
+- Add `set_to_localstorage` parameter to `leptos_fluent!` macro.
+- Add `use_i18n` and `expect_i18n` function.
+
+### Breaking changes
+
+- Replace `I18n.set_language_with_localstorage` method with
+ `I18n.set_language`. Use `set_to_localstorage` macro parameter
+ and `I18n.set_language` instead.
+- Remove `csr` feature.
+
+### Bug fixes
+
+- Fix errors getting initial language from URL parameter and local storage.
+
## 2024-05-18 - [0.0.23]
- Add `axum` feature to integrate with Axum web framework.
@@ -44,6 +65,7 @@
- Added all ISO-639-1 and ISO-639-2 languages.
+[0.0.24]: https://github.com/mondeja/leptos-fluent/compare/v0.0.23...v0.0.24
[0.0.23]: https://github.com/mondeja/leptos-fluent/compare/v0.0.22...v0.0.23
[0.0.22]: https://github.com/mondeja/leptos-fluent/compare/v0.0.21...v0.0.22
[0.0.21]: https://github.com/mondeja/leptos-fluent/compare/v0.0.20...v0.0.21
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 2738b4a8..0238e9bb 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -21,10 +21,17 @@ wasm-pack test --{browser} --headless
Where `{browser}` is one of `firefox`, `chrome`, or `safari`. For example:
```sh
-cd tests
+cd end2end
wasm-pack test --firefox --headless
```
+If you want to run a test suite:
+
+```sh
+cd end2end
+wasm-pack test --firefox --headless --test csr_minimal
+```
+
## Documentation
```sh
diff --git a/Cargo.lock b/Cargo.lock
index e1d44436..f686aca7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1428,10 +1428,8 @@ dependencies = [
[[package]]
name = "leptos-fluent"
-version = "0.0.23"
+version = "0.0.24"
dependencies = [
- "actix-web",
- "axum",
"cfg-if",
"fluent-templates",
"leptos",
@@ -1464,14 +1462,13 @@ dependencies = [
[[package]]
name = "leptos-fluent-macros"
-version = "0.0.23"
+version = "0.0.24"
dependencies = [
"cfg-if",
"proc-macro2",
"quote",
"serde_json",
"syn 2.0.64",
- "web-sys",
]
[[package]]
@@ -1514,13 +1511,11 @@ dependencies = [
name = "leptos-fluent-tests"
version = "0.1.0"
dependencies = [
- "js-sys",
"leptos",
"leptos-fluent-csr-complete-example",
"leptos-fluent-csr-minimal-example",
- "wasm-bindgen-futures",
+ "tests-helpers",
"wasm-bindgen-test",
- "web-sys",
]
[[package]]
@@ -2586,6 +2581,16 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
+[[package]]
+name = "tests-helpers"
+version = "0.1.0"
+dependencies = [
+ "js-sys",
+ "leptos",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
[[package]]
name = "thiserror"
version = "1.0.61"
diff --git a/Cargo.toml b/Cargo.toml
index b16513b4..b869f07e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,7 +2,8 @@
members = [
"leptos-fluent",
"leptos-fluent-macros",
- "tests",
+ "end2end",
+ "end2end/tests-helpers",
"examples/csr-complete",
"examples/csr-minimal",
"examples/ssr-hydrate-actix",
diff --git a/README.md b/README.md
index 19c7cd19..12027616 100644
--- a/README.md
+++ b/README.md
@@ -18,12 +18,13 @@ Add the following to your `Cargo.toml` file:
```toml
[dependencies]
-leptos-fluent = "0.0.21"
+leptos-fluent = "0.0.24"
fluent-templates = "0.9"
[features]
-csr = ["leptos-fluent/csr"]
-hydrate = ["leptos-fluent/hydrate"]
+hydrate = [
+ "leptos-fluent/hydrate"
+]
ssr = [
"leptos-fluent/ssr",
"leptos-fluent/actix", # actix and axum are supported
@@ -101,6 +102,9 @@ pub fn App() -> impl IntoView {
// Get the initial language from `navigator.languages` if not
// found in the local storage. By default, it is `false`.
initial_language_from_navigator: true,
+ // Set the language to local storage when the user changes it.
+ // By default, it is `false`.
+ set_to_localstorage: true,
// Name of the field in local storage to get and set the
// current language of the user. By default, it is `"lang"`.
localstorage_key: "language",
@@ -134,8 +138,7 @@ fn ChildComponent() -> impl IntoView {
### Features
-- **Client side rendering (CSR)**: Use the `leptos-fluent/csr` feature.
-- **Server side rendering (SSR)**: Use the `leptos-fluent/ssr` feature.
+- **Server Side Rendering**: Use the `leptos-fluent/ssr` feature.
- **Hydration**: Use the `leptos-fluent/hydrate` feature.
- **Actix Web integration**: Use the `leptos-fluent/actix` feature.
- **Axum integration**: Use the `leptos-fluent/axum` feature.
diff --git a/tests/Cargo.toml b/end2end/Cargo.toml
similarity index 75%
rename from tests/Cargo.toml
rename to end2end/Cargo.toml
index a008df49..d1ae2fe9 100644
--- a/tests/Cargo.toml
+++ b/end2end/Cargo.toml
@@ -3,14 +3,9 @@ name = "leptos-fluent-tests"
edition = "2021"
version = "0.1.0"
-[lib]
-crate-type = ["cdylib"]
-
[dependencies]
+tests-helpers = { path = "./tests-helpers" }
leptos-fluent-csr-minimal-example = { path = "../examples/csr-minimal" }
leptos-fluent-csr-complete-example = { path = "../examples/csr-complete" }
wasm-bindgen-test = "0.3"
leptos = "0.6"
-js-sys = "0.3"
-web-sys = "0.3"
-wasm-bindgen-futures = "0.4"
diff --git a/end2end/tests-helpers/Cargo.toml b/end2end/tests-helpers/Cargo.toml
new file mode 100644
index 00000000..b02ff004
--- /dev/null
+++ b/end2end/tests-helpers/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "tests-helpers"
+edition = "2021"
+version = "0.1.0"
+
+[dependencies]
+leptos = "0.6"
+web-sys = { version = "0.3", features = ["Navigator", "Storage"] }
+js-sys = "0.3"
+wasm-bindgen-futures = "0.4"
diff --git a/end2end/tests-helpers/src/lib.rs b/end2end/tests-helpers/src/lib.rs
new file mode 100644
index 00000000..f2981aec
--- /dev/null
+++ b/end2end/tests-helpers/src/lib.rs
@@ -0,0 +1,93 @@
+#[macro_export]
+macro_rules! mount {
+ ($app:ident) => {{
+ ::leptos::mount_to_body(
+ move || ::leptos::view! {
<$app/>
},
+ );
+ }};
+}
+
+#[macro_export]
+macro_rules! unmount {
+ () => {{
+ use leptos::wasm_bindgen::JsCast;
+ ::leptos::document()
+ .body()
+ .unwrap()
+ .remove_child(
+ ::leptos::document()
+ .get_element_by_id("wrapper")
+ .unwrap()
+ .unchecked_ref(),
+ )
+ .unwrap();
+ }};
+}
+
+pub async fn sleep(delay: i32) {
+ let mut cb = |resolve: js_sys::Function, _reject: js_sys::Function| {
+ ::web_sys::window()
+ .unwrap()
+ .set_timeout_with_callback_and_timeout_and_arguments_0(
+ &resolve, delay,
+ )
+ .unwrap();
+ };
+
+ let p = ::js_sys::Promise::new(&mut cb);
+ ::wasm_bindgen_futures::JsFuture::from(p).await.unwrap();
+}
+
+pub fn element_text(selector: &str) -> String {
+ ::leptos::document()
+ .query_selector(selector)
+ .unwrap()
+ .unwrap()
+ .text_content()
+ .unwrap()
+}
+
+pub fn input_by_id(id: &str) -> web_sys::HtmlInputElement {
+ use leptos::wasm_bindgen::JsCast;
+ ::leptos::document()
+ .get_element_by_id(id)
+ .unwrap()
+ .unchecked_into::()
+}
+
+pub fn html() -> web_sys::HtmlHtmlElement {
+ use leptos::wasm_bindgen::JsCast;
+ ::leptos::document()
+ .document_element()
+ .unwrap()
+ .unchecked_into::()
+}
+
+pub mod localstorage {
+ pub fn delete(key: &str) {
+ ::leptos::window()
+ .local_storage()
+ .unwrap()
+ .unwrap()
+ .remove_item(key)
+ .unwrap();
+ }
+
+ pub fn set(key: &str, value: &str) {
+ ::leptos::window()
+ .local_storage()
+ .unwrap()
+ .unwrap()
+ .set_item(key, value)
+ .unwrap();
+ }
+
+ pub fn get(key: &str) -> Option {
+ ::leptos::window()
+ .local_storage()
+ .unwrap()
+ .unwrap()
+ .get_item(key)
+ .unwrap()
+ }
+}
diff --git a/end2end/tests/csr_complete.rs b/end2end/tests/csr_complete.rs
new file mode 100644
index 00000000..efc98c97
--- /dev/null
+++ b/end2end/tests/csr_complete.rs
@@ -0,0 +1,54 @@
+use tests_helpers::{
+ element_text, html, input_by_id, localstorage, mount, sleep, unmount,
+};
+use wasm_bindgen_test::*;
+
+wasm_bindgen_test_configure!(run_in_browser);
+
+#[wasm_bindgen_test]
+async fn csr_complete_example() {
+ use leptos_fluent_csr_complete_example::App as CompleteExampleApp;
+ localstorage::delete("language");
+
+ mount!(CompleteExampleApp);
+ let es = move || input_by_id("es");
+ let en = move || input_by_id("en");
+
+ // translations working
+ assert!(en().checked());
+ assert!(!es().checked());
+ assert_eq!(element_text("p"), "Select a language:");
+ es().click();
+ assert!(es().checked());
+ assert!(!en().checked());
+ assert_eq!(element_text("p"), "Selecciona un idioma:");
+ en().click();
+ assert!(en().checked());
+ assert_eq!(element_text("p"), "Select a language:");
+ assert!(!es().checked());
+
+ // sync_html_tag_lang
+ es().click();
+ sleep(30).await;
+ assert!(es().checked());
+ assert_eq!(html().lang(), "es".to_string());
+ en().click();
+ sleep(30).await;
+ assert_eq!(html().lang(), "en".to_string());
+
+ // set_to_localstorage
+ localstorage::delete("language");
+ assert_eq!(localstorage::get("language"), None);
+ es().click();
+ assert_eq!(localstorage::get("language"), Some("es".to_string()));
+ en().click();
+ assert_eq!(localstorage::get("language"), Some("en".to_string()));
+
+ // TODO:
+ // initial_language_from_url
+ // initial_language_from_url_to_localstorage
+ // initial_language_from_localstorage
+ // initial_language_from_navigator
+
+ unmount!();
+}
diff --git a/end2end/tests/csr_minimal.rs b/end2end/tests/csr_minimal.rs
new file mode 100644
index 00000000..f3125b70
--- /dev/null
+++ b/end2end/tests/csr_minimal.rs
@@ -0,0 +1,37 @@
+use tests_helpers::{
+ element_text, html, input_by_id, localstorage, mount, sleep, unmount,
+};
+use wasm_bindgen_test::*;
+
+wasm_bindgen_test_configure!(run_in_browser);
+
+#[wasm_bindgen_test]
+async fn csr_minimal_example() {
+ use leptos_fluent_csr_minimal_example::App as MinimalExampleApp;
+ mount!(MinimalExampleApp);
+ let es = move || input_by_id("es");
+ let en = move || input_by_id("en");
+
+ // localstorage not activated
+ localstorage::set("language", "es");
+
+ // translations working
+ assert_eq!(element_text("p"), "Select a language:");
+ es().click();
+ assert!(es().checked());
+ assert!(!en().checked());
+ assert_eq!(element_text("p"), "Selecciona un idioma:");
+
+ // language change not reflected in html tag
+ sleep(30).await;
+ html().remove_attribute("lang").unwrap();
+ assert_eq!(html().lang(), "".to_string());
+ es().click();
+ assert!(es().checked());
+ assert_eq!(html().lang(), "".to_string());
+ en().click();
+ assert!(en().checked());
+ assert_eq!(html().lang(), "".to_string());
+
+ unmount!();
+}
diff --git a/examples/csr-complete/Cargo.toml b/examples/csr-complete/Cargo.toml
index 3da9cba9..62c6581f 100644
--- a/examples/csr-complete/Cargo.toml
+++ b/examples/csr-complete/Cargo.toml
@@ -9,7 +9,7 @@ path = "src/lib.rs"
[dependencies]
leptos = {version = "0.6", features = ["csr"]}
-leptos-fluent = { path = "../../leptos-fluent", features = ["csr"] }
+leptos-fluent = { path = "../../leptos-fluent" }
fluent-templates = "0.9"
console_error_panic_hook = "0"
web-sys = "0"
diff --git a/examples/csr-complete/src/lib.rs b/examples/csr-complete/src/lib.rs
index 0347fc20..1e1c3468 100644
--- a/examples/csr-complete/src/lib.rs
+++ b/examples/csr-complete/src/lib.rs
@@ -1,6 +1,6 @@
use fluent_templates::static_loader;
use leptos::*;
-use leptos_fluent::{i18n, leptos_fluent, move_tr, Language};
+use leptos_fluent::{expect_i18n, leptos_fluent, move_tr, Language};
static_loader! {
static TRANSLATIONS = {
@@ -20,6 +20,7 @@ pub fn App() -> impl IntoView {
initial_language_from_url_to_localstorage: true,
initial_language_from_localstorage: true,
initial_language_from_navigator: true,
+ set_to_localstorage: true,
localstorage_key: "language",
}};
@@ -28,14 +29,14 @@ pub fn App() -> impl IntoView {
#[component]
fn ChildComponent() -> impl IntoView {
- let i18n = i18n();
+ let i18n = expect_i18n();
view! {
{move_tr!("select-a-language")}