Skip to content

Commit

Permalink
Merge pull request #182 from Baptistemontan/dyn_load_csr
Browse files Browse the repository at this point in the history
CSR dynamic loading
  • Loading branch information
Baptistemontan authored Jan 11, 2025
2 parents d8b7194 + b2ae554 commit a7c8844
Show file tree
Hide file tree
Showing 42 changed files with 985 additions and 100 deletions.
81 changes: 74 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ on:
- master
env:
CARGO_TERM_COLOR: always
CARGO_LEPTOS_VERSION: 0.2.22
jobs:
lib_test:
name: Test leptos_i18n package
Expand Down Expand Up @@ -52,7 +51,14 @@ jobs:
strategy:
fail-fast: false
matrix:
examples: [hello_world_actix, hello_world_axum, workspace, axum_island, routing_ssr]
examples:
[
hello_world_actix,
hello_world_axum,
workspace,
axum_island,
routing_ssr,
]
steps:
- name: "Checkout repo"
uses: actions/checkout@v4
Expand All @@ -66,7 +72,7 @@ jobs:
toolchain: "stable"
targets: "wasm32-unknown-unknown"
- name: "Install cargo-leptos"
run: cargo install cargo-leptos@${{ env.CARGO_LEPTOS_VERSION }} --locked
run: cargo install cargo-leptos
- name: "Build ${{ matrix.examples }} example"
working-directory: examples/ssr/${{ matrix.examples }}
run: cargo leptos build
Expand All @@ -89,8 +95,8 @@ jobs:
with:
name: playwright-report-${{ matrix.examples }}
path: examples/ssr/${{ matrix.examples }}/playwright-report/
test_dyn_load_examples:
name: Test ${{ matrix.examples }} dynamic_load example
test_ssr_dyn_load_examples:
name: Test ${{ matrix.examples }} dyn load SSR example
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand All @@ -109,7 +115,7 @@ jobs:
toolchain: "stable"
targets: "wasm32-unknown-unknown"
- name: "Install cargo-leptos"
run: cargo install cargo-leptos@${{ env.CARGO_LEPTOS_VERSION }} --locked
run: cargo install cargo-leptos
- name: "Build ${{ matrix.examples }} example"
working-directory: examples/dynamic_load/${{ matrix.examples }}
run: cargo leptos build
Expand All @@ -132,13 +138,74 @@ jobs:
with:
name: playwright-report-${{ matrix.examples }}
path: examples/dynamic_load/${{ matrix.examples }}/playwright-report/
test_csr_dyn_load_examples:
name: Test ${{ matrix.examples }} dyn load CSR example
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
examples: [csr_counter]
steps:
- name: "Checkout repo"
uses: actions/checkout@v4
- name: "Setup Node"
uses: actions/setup-node@v4
with:
node-version: 18
- name: "Setup Rust toolchain"
uses: dtolnay/rust-toolchain@stable
with:
toolchain: "stable"
targets: "wasm32-unknown-unknown"
- name: "Install trunk"
run: cargo install trunk --locked
# FIXME: This tep is due to the fact that `trunk build` call the build script after the asset pipeline
# So the translations generated by it are not found and cause an error
# We thus use `cargo build` to run the build script once before `trunk build`.
- name: "Pre-Build ${{ matrix.examples }} example"
working-directory: examples/dynamic_load/${{ matrix.examples }}
run: cargo build
- name: "Build ${{ matrix.examples }} example"
working-directory: examples/dynamic_load/${{ matrix.examples }}
run: trunk build
- name: "Build e2e utils"
working-directory: examples/utils
run: npm ci
- name: "Install Playwright"
working-directory: examples/dynamic_load/${{ matrix.examples }}
run: |
npm ci
npx playwright install --with-deps
- name: "e2e testing ${{ matrix.examples }} example"
id: e2e
working-directory: examples/dynamic_load/${{ matrix.examples }}
run: npx playwright test
- name: "Upload e2e report"
uses: actions/upload-artifact@v4
# upload artifact only if e2e test failed
if: ${{ steps.e2e.outcome == 'failure' && !cancelled() }}
with:
name: playwright-report-${{ matrix.examples }}
path: examples/dynamic_load/${{ matrix.examples }}/playwright-report/
test_csr_examples:
name: Test ${{ matrix.examples }} CSR example
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
examples: [counter, counter_icu_datagen, counter_plurals, counter_ranges, interpolation, namespaces, subkeys, yaml, routing_csr, subcontext]
examples:
[
counter,
counter_icu_datagen,
counter_plurals,
counter_ranges,
interpolation,
namespaces,
subkeys,
yaml,
routing_csr,
subcontext,
]
steps:
- name: "Checkout repo"
uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion docs/book/src/reduce_size/01_datagen.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ when all information is already in the translations.
```toml
# Cargo.toml
[build-dependencies]
leptos_i18n_build = "0.5.0-gamma2"
leptos_i18n_build = "0.5.0"
```

```rust
Expand Down
77 changes: 74 additions & 3 deletions docs/book/src/reduce_size/02_dynamic_load.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,85 @@ use leptos_i18n::Locale as LocaleTrait;
register_server_fn::<<Locale as LocaleTrait>::ServerFn>();
```

## Final note
### CSR

Other than that, this is mostly a drop-in feature and does not require much from the user.
With SSR the translations are served by a server functions, but they don't exist with CSR, so you will need to create a static JSON containing them, so a bit more work is needed.
To do that you can use a build script and use the `leptos_i18n_build` crate:

```toml
# Cargo.toml
[build-dependencies]
leptos_i18n_build = "0.5.0"
```

```rust
use leptos_i18n_build::TranslationsInfos;

fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=Cargo.toml");

let translations_infos = TranslationsInfos::parse().unwrap();

translations_infos.rerun_if_locales_changed();

translations_infos
.get_translations()
.write_to_dir("path/to/dir")
.unwrap();
}
```

This will generate the need JSON files in the given directory, for exemple you could generate them in `target/i18n`, giving this file structure:

```bash
./target
└── i18n
├── locale1.json
└── locale2.json
```

If you are using namespaces it would have this one:

```bash
./target
└── i18n
└── namespace1
├── locale1.json
└── locale2.json
└── namespace2
├── locale1.json
└── locale2.json
```

Then if you are using Trunk you just have to add the directory to the build pipeline:

```html
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<link data-trunk rel="copy-dir" href="./target/i18n" />
</head>
<body></body>
</html>
```

Now the translations will be available at `i18n/{locale}.json`
To inform `leptos_i18n` where to find those translations you need to supply the `translations-uri` field under `[package.metadata.leptos-i18n]`:

```toml
# Cargo.toml
[package.metadata.leptos-i18n]
translations-uri = "i18n/{locale}.json" # or "i18n/{namespace}/{locale}.json" when using namespaces
```

And this is it!

## Disclaimers

1. There is a chance that enabling this feature actually increases binary sizes if there aren’t many translations,
as there is additional code being generated to request, parse, and load the translations. But this is mostly a fixed cost,
so with enough translations, the trade will be beneficial. So do some testing.

2. Only the raw strings are removed from the binary; the code to display each key is still baked in it, whatever the locale or the namespace.
2. Only the raw strings are removed from the binary; the code to render each key is still baked in it, whatever the locale or the namespace.
10 changes: 4 additions & 6 deletions examples/dynamic_load/axum_island/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,27 @@ crate-type = ["cdylib", "rlib"]

[dependencies]
axum = { version = "0.7", optional = true }
leptos = { version = "0.7.0-beta", features = ["islands"] }
leptos_meta = { version = "0.7.0-beta" }
leptos_axum = { version = "0.7.0-beta", optional = true }
leptos = { version = "0.7.3", features = ["islands"] }
leptos_meta = { version = "0.7.3" }
leptos_axum = { version = "0.7.3", optional = true }
leptos_i18n = { path = "../../../leptos_i18n", features = [
"track_locale_files",
"islands",
"dynamic_load",
] }
serde = { version = "1", features = ["derive"] }
console_error_panic_hook = { version = "0.1", optional = true }
# wasm-bindgen = { version = "0.2", optional = true }
wasm-bindgen = "0.2"
simple_logger = "4"
tokio = { version = "1.35", features = ["rt-multi-thread"], optional = true }
log = "0.4"
tower = { version = "0.5.1", optional = true }
tower-http = { version = "0.6.1", features = ["fs"], optional = true }
wasm-bindgen = "=0.2.96"

[features]
default = ["hydrate", "ssr"]
hydrate = [
"dep:console_error_panic_hook",
# "dep:wasm-bindgen",
"leptos/hydrate",
"leptos_i18n/hydrate",
]
Expand Down
9 changes: 9 additions & 0 deletions examples/dynamic_load/csr_counter/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Cargo.lock
target
dist
!.vscode
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
5 changes: 5 additions & 0 deletions examples/dynamic_load/csr_counter/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"recommendations": [
"lokalise.i18n-ally",
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
languageIds:
- rust

usageMatchRegex:
- "[^\\w\\d]t!\\(\\s*[\\w.:]*,\\s*([\\w.]*)"
- "[^\\w\\d]td!\\(\\s*[\\w.:]*,\\s*([\\w.]*)"
- "[^\\w\\d]td_string!\\(\\s*[\\w.:]*,\\s*([\\w.]*)"
- "[^\\w\\d]td_display!\\(\\s*[\\w.:]*,\\s*([\\w.]*)"

monopoly: true
5 changes: 5 additions & 0 deletions examples/dynamic_load/csr_counter/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"i18n-ally.keystyle": "nested",
"i18n-ally.localesPaths": "locales",
"rust-analyzer.cargo.buildScripts.enable": true
}
26 changes: 26 additions & 0 deletions examples/dynamic_load/csr_counter/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "csr_counter"
version = "0.1.0"
edition = "2021"

[dependencies]
leptos = { version = "0.7.0", features = ["csr"] }
leptos_i18n = { path = "../../../leptos_i18n", features = [
"csr",
"plurals",
"dynamic_load",
"track_locale_files",
] }
console_error_panic_hook = { version = "0.1" }

[package.metadata.leptos-i18n]
default = "en"
locales = ["en", "fr"]
translations-uri = "i18n/{locale}.json"

[build-dependencies]
leptos_i18n_build = { path = "../../../leptos_i18n_build" }

[profile.release]
opt-level = "z"
lto = true
11 changes: 11 additions & 0 deletions examples/dynamic_load/csr_counter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Dynamic Load CSR Counter Example

This example showcase how you can use dynamic load with CSR.

## How to run

Simply use `trunk` to run it:

```bash
trunk serve --open
```
15 changes: 15 additions & 0 deletions examples/dynamic_load/csr_counter/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use leptos_i18n_build::TranslationsInfos;

fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=Cargo.toml");

let translations_infos = TranslationsInfos::parse().unwrap();

translations_infos.rerun_if_locales_changed();

translations_infos
.get_translations()
.write_to_dir("./target/i18n")
.unwrap();
}
Loading

0 comments on commit a7c8844

Please sign in to comment.