Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Track locales files in proc macro #93

Merged
merged 6 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,7 @@ The `cookie` feature enable to set a cookie when a locale is chosen by the user,
The `serde` feature implement `serde::Serialize` and `serde::Deserialize` for the locale enum.

The `nightly` feature enable to do `i18n()` to get the locale instead of `i18n.get_locale()` and `i18n(new_locale)` instead of `i18n.set_locale(new_locale)`.
It also allow macros to use unstable APIs for better warnings.

The `debug_interpolations` feature enable the macros to generate code to emit a warning if a key is supplied twice in interpolations and a better compilation error when a key is missing.
Better compilation errors are generated for interpolations with 4 keys or less.
Expand All @@ -607,6 +608,12 @@ The `json_files` feature tell the macro to expect JSON files for the locales, en

The `yaml_files` feature tell the macro to expect YAML files for the locales

The `track_locale_files` feature is to track files for rebuilds. The `load_locales!()` macro using external dependencies the build system is not aware that the macro should be rerun when those files changes,
you may have noticed that if you use `cargo-leptos` with `watch-additional-files = ["locales"]` and running `cargo leptos watch`, even if the file changes and cargo-leptos triggers a rebuild nothing changes.
This feature use a "trick" by using `include_bytes!()` to declare the use of a file, but I'm a bit sceptical of the impact on build time using this.
I've already checked and it does not include the bytes in the final binary, even in debug, but it may slow down compilation time.
If you use the `nighly` feature it use the [path tracking API](https://github.com/rust-lang/rust/issues/99515) so no trick using `include_bytes!` and the possible slowdown in compile times coming with it.

## Contributing

Errors are a bit clunky or obscure for now, there is a lot of edge cases and I did not had time to track every failing scenario, feel free to open an issue on github so I can improve those.
Expand Down
12 changes: 11 additions & 1 deletion docs/book/src/06_features.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,14 @@ Set a cookie to remember the last chosen locale.

#### `nightly`

Enable the use of some nighly features, like directly calling the context to get/set the current locale, also allow the `load_locale!` macro to emit better warnings.
- Enable the use of some nighly features, like directly calling the context to get/set the current locale.
- Allow the `load_locale!` macro to emit better warnings.

#### `track_locale_files`

Allow tracking of locale files as dependencies for rebuilds in stable.
The `load_locales!()` macro using external dependencies the build system is not aware that the macro should be rerun when those files changes,
you may have noticed that if you use `cargo-leptos` with `watch-additional-files = ["locales"]` and running `cargo leptos watch`, even if the file changes and cargo-leptos triggers a rebuild nothing changes.
This feature use a "trick" by using `include_bytes!()` to declare the use of a file, but I'm a bit sceptical of the impact on build time using this.
I've already checked and it does not include the bytes in the final binary, even in debug, but it may slow down compilation time.
If you use the `nighly` feature it use the [path tracking API](https://github.com/rust-lang/rust/issues/99515) so no trick using `include_bytes!` and the possible slowdown in compile times coming with it.
7 changes: 7 additions & 0 deletions examples/hello_world_actix/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ leptos_meta = "0.6"
leptos_actix = { version = "0.6.0", optional = true }
leptos_i18n = { path = "../../leptos_i18n", features = [
"debug_interpolations",
"track_locale_files",
] }
serde = { version = "1", features = ["derive"] }
console_error_panic_hook = { version = "0.1", optional = true }
Expand Down Expand Up @@ -87,5 +88,11 @@ lib-features = ["hydrate"]
# Optional. Defaults to false.
lib-default-features = false

# Additional files your application could depends on.
# A change to any file in those directories will trigger a rebuild.
#
# Optional.
watch-additional-files = ["locales"]

[package.metadata.cargo-all-features]
skip_feature_sets = [["hydrate", "ssr"]]
7 changes: 7 additions & 0 deletions examples/hello_world_axum/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ leptos_meta = "0.6"
leptos_axum = { version = "0.6", optional = true }
leptos_i18n = { path = "../../leptos_i18n", features = [
"debug_interpolations",
"track_locale_files",
] }
serde = { version = "1", features = ["derive"] }
console_error_panic_hook = { version = "0.1", optional = true }
Expand Down Expand Up @@ -93,5 +94,11 @@ lib-features = ["hydrate"]
# Optional. Defaults to false.
lib-default-features = false

# Additional files your application could depends on.
# A change to any file in those directories will trigger a rebuild.
#
# Optional.
watch-additional-files = ["locales"]

[package.metadata.cargo-all-features]
skip_feature_sets = [["hydrate", "ssr"]]
2 changes: 2 additions & 0 deletions leptos_i18n/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ suppress_key_warnings = ["leptos_i18n_macro/suppress_key_warnings"]
json_files = ["leptos_i18n_macro/json_files"]
yaml_files = ["leptos_i18n_macro/yaml_files"]
interpolate_display = ["leptos_i18n_macro/interpolate_display"]
track_locale_files = ["leptos_i18n_macro/track_locale_files"]


[package.metadata.cargo-all-features]
Expand All @@ -50,6 +51,7 @@ denylist = [
"serde",
"debug_interpolations",
"suppress_key_warnings",
"track_locale_files",
]
skip_feature_sets = [
# Axum and Actix features are incompatible with each other - see `./src/server/mod.rs`, always exclude:
Expand Down
1 change: 1 addition & 0 deletions leptos_i18n/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
//! - `suppress_key_warnings`: Disable the warning emission of the `load_locales!()` macro when some keys are missing or ignored.
//! - `yaml_files`: Enable this feature if you use YAML files for declaring your locales (can't be used with `json_files`).
//! - `nightly`: On `nightly` Rust, enables the function-call syntax on the i18n context to get/set the locale.
//! - `track_locale_files`: Enable the tracking of locale files as dependencies, usefull if you use some watcher. See the README for more infos.
//!
//! # A Simple Counter
//!
Expand Down
1 change: 1 addition & 0 deletions leptos_i18n_macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ suppress_key_warnings = []
json_files = ["serde_json"]
yaml_files = ["serde_yaml"]
interpolate_display = []
track_locale_files = []

[package.metadata.cargo-all-features]
# cargo-all-features don't provide a way to always include one feature in a set, so CI will just do json...
Expand Down
2 changes: 1 addition & 1 deletion leptos_i18n_macro/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![deny(missing_docs)]
#![forbid(unsafe_code)]
#![deny(warnings)]
#![cfg_attr(feature = "nightly", feature(proc_macro_diagnostic))]
#![cfg_attr(feature = "nightly", feature(proc_macro_diagnostic, track_path))]
//! # About Leptos i18n macro
//!
//! This crate expose the utility macro for `leptos_i18n`
Expand Down
3 changes: 3 additions & 0 deletions leptos_i18n_macro/src/load_locales/locale.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use super::{
error::{Error, Result},
key::{Key, KeyPath},
parsed_value::{InterpolateKey, ParsedValue, ParsedValueSeed},
tracking::track_file,
warning::{emit_warning, Warning},
};

Expand Down Expand Up @@ -190,6 +191,8 @@ impl Locale {
locale: Rc<Key>,
namespace: Option<Rc<Key>>,
) -> Result<Self> {
track_file(&locale, namespace.as_ref(), path);

let seed = LocaleSeed {
name: Rc::clone(&locale),
top_locale_name: locale,
Expand Down
5 changes: 5 additions & 0 deletions leptos_i18n_macro/src/load_locales/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub mod key;
pub mod locale;
pub mod parsed_value;
pub mod plural;
pub mod tracking;
pub mod warning;

use cfg_file::ConfigFile;
Expand Down Expand Up @@ -67,8 +68,12 @@ pub fn load_locales() -> Result<TokenStream> {
)
};

let file_tracking = tracking::generate_file_tracking();

Ok(quote! {
pub mod i18n {
#file_tracking

#locale_enum

#locale_type
Expand Down
56 changes: 56 additions & 0 deletions leptos_i18n_macro/src/load_locales/tracking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use std::{path::PathBuf, rc::Rc};

use super::key::Key;

#[cfg(feature = "track_locale_files")]
mod inner {
use super::*;

#[cfg(not(feature = "nightly"))]
thread_local! {
pub static LOCALES_PATH: std::cell::RefCell<Vec<String>> = const { std::cell::RefCell::new(Vec::new()) };
}

#[cfg(not(feature = "nightly"))]
pub fn generate_file_tracking() -> proc_macro2::TokenStream {
LOCALES_PATH.with_borrow(
|paths| quote::quote!(#(const _: &'static [u8] = include_bytes!(#paths);)*),
)
}

#[cfg(feature = "nightly")]
pub fn generate_file_tracking() -> proc_macro2::TokenStream {
proc_macro2::TokenStream::new()
}

pub fn track_file(locale: &Rc<Key>, namespace: Option<&Rc<Key>>, path: &PathBuf) {
use crate::load_locales::warning::{emit_warning, Warning};
if let Some(path) = path.as_os_str().to_str() {
#[cfg(not(feature = "nightly"))]
LOCALES_PATH.with_borrow_mut(|paths| paths.push(path.to_owned()));
#[cfg(feature = "nightly")]
proc_macro::tracked_path::path(path);
} else {
emit_warning(Warning::NonUnicodePath {
locale: locale.clone(),
namespace: namespace.cloned(),
path: path.clone(),
});
}
}
}

#[cfg(not(feature = "track_locale_files"))]
mod inner {
use super::*;

pub fn generate_file_tracking() -> proc_macro2::TokenStream {
proc_macro2::TokenStream::new()
}

pub fn track_file(locale: &Rc<Key>, namespace: Option<&Rc<Key>>, path: &PathBuf) {
let _ = (locale, namespace, path);
}
}

pub use inner::*;
20 changes: 18 additions & 2 deletions leptos_i18n_macro/src/load_locales/warning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,20 @@ use std::{cell::RefCell, fmt::Display, rc::Rc};

#[derive(Debug)]
pub enum Warning {
MissingKey { locale: Rc<Key>, key_path: KeyPath },
SurplusKey { locale: Rc<Key>, key_path: KeyPath },
MissingKey {
locale: Rc<Key>,
key_path: KeyPath,
},
SurplusKey {
locale: Rc<Key>,
key_path: KeyPath,
},
#[cfg(feature = "track_locale_files")]
NonUnicodePath {
locale: Rc<Key>,
namespace: Option<Rc<Key>>,
path: std::path::PathBuf,
},
}

thread_local! {
Expand All @@ -32,6 +44,10 @@ impl Display for Warning {
"Key {} is present in locale {:?} but not in default locale, it is ignored",
key_path, locale
),
#[cfg(feature = "track_locale_files")]
Warning::NonUnicodePath { locale, namespace: None, path } => write!(f, "File path for locale {:?} is not valid Unicode, can't add it to proc macro depedencies. Path: {:?}", locale, path),
#[cfg(feature = "track_locale_files")]
Warning::NonUnicodePath { locale, namespace: Some(ns), path } => write!(f, "File path for locale {:?} in namespace {:?} is not valid Unicode, can't add it to proc macro depedencies. Path: {:?}", locale, ns, path),
}
}
}
Expand Down
Loading