Code Monkey home page Code Monkey logo

leptos_i18n's People

Contributors

ad4mantis avatar baptistemontan avatar brofrain avatar maneac avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

leptos_i18n's Issues

Cannot load locales when inside a Workspace

I get: error: Could not found "[package.metadata.leptos-i18n]" in cargo manifest (Cargo.toml), when calling leptos_i18n::load_locales!();. I think there's a problem when trying to load the locales when inside a worspace? Or maybe I just missunderstood something and am placing my metadata in the wrong place?

Here is my folder structure:

frontend/
├─ api_sdk/
│  ├─ .../
├─ app/
│  ├─ src/
│  │  ├─ main.rs
│  │  ├─ ...
│  ├─ translations/
│  ├─ Cargo.toml
│  ├─ index.html
├─ Cargo.toml

The app/ folder is where is my leptos code code and I am trying to use leptos_i18n. Here is my setup:

# frontend/Cargo.toml
[workspace]
resolver = "2"
members = ["app", "api_sdk"]
default-members = ["app"]
# frontend/app/Cargo.toml
[package]
name = "app"
version = "0.1.0"
edition = "2021"

[package.metadata.leptos-i18n]
default = "en"
locales = ["en", "fr"]
locales-dir = "./translations"

[dependencies.leptos]
version = "0.5.0-rc1"
features = ["csr", "tracing"]

[dependencies.leptos_i18n]
version = "0.2.0-beta5"

And so I am trying to call leptos_i18n::load_locales!(); inside frontend/app/src/main.rs and I get the error specified.

Don't crash on missing keys

I'm getting a lot of the error:

error: Some keys are different beetween locale files, "bn.json" is missing key: "....."

Translations are nearly always a work in progress, and based on a source language. These should be warnings, not hard errors, and automatically fallback to the default.

t_string! raises an ERROR

Hi,

when testing the t_string! functionality with an enhanced examples/csr/src/app.rs

let inc = move |_| set_counter.update(|count| *count += 1);
    
    let count = move || counter.get();
    
    assert_eq!(t_string!(i18n, click_count, count ),"You clicked 0 times");     // New, to test t_string!
    
    view! {
        <p>{t!(i18n, click_count, count)}</p>
        // <p>{t!(i18n, click_count, count = move || counter.get())}</p>
        <button on:click=inc>{t!(i18n, click_to_inc)}</button>

I did experience the following issue (Note: feature "interpolate_display" has beenenabled in Cargo.toml) :

error[E0599]: no method named `var_count_string` found for struct `click_count_builder` in the current scope
  --> src/app.rs:34:45
   |
34 |     assert_eq!(t_string!(i18n, click_count, count ),"You clicked 0 times");
   |                                             ^^^^^
   |
  ::: src/main.rs:4:1
   |
4  | leptos_i18n::load_locales!();
   | ---------------------------- method `var_count_string` not found for this struct
   |
help: there is a method `var_count` with a similar name
   |
34 |     assert_eq!(t_string!(i18n, click_count, var_count ),"You clicked 0 times");
   |                                             ~~~~~~~~~

For more information about this error, try `rustc --explain E0599`.
error: could not compile `csr` (bin "csr") due to 1 previous error
2024-05-14T12:09:57.122064Z ERROR ❌ error

Any suggestion what I'm doing wrong. Here my toolchain, I'm using most actual i18n version

active toolchain
----------------

stable-x86_64-unknown-linux-gnu (default)
rustc 1.78.0 (9b00956e5 2024-04-29)

Thank you in advance
BR

Migrating from `i18n.json` to `Cargo.toml`

Currently the config file is i18n.json, but it would be better to put the configurations in the Cargo manifest, like cargo-leptos does it.

So instead of

i18n.json:

{
    "default": "en",
    "locales": ["en", "fr"]
}

we would have

Cargo.toml:

[package.metadata.i18n]
default = "en"
locales = ["en", "fr"]

This would be a breaking changes, but I would like to bring it to v0.2.0

Setting to display the key during dev

It would be great if you could force the t! macro to display the key (and interpolations) rather than actually translating. This is to help find any untranslated strings that may have crept in.

`hydrate` and `ssr` features are incompatible

Overview

The hydrate and ssr features define competing implementations of fetch_locale, so they cannot both be enabled at the same time.
For example, when enabling leptos_i18n in a multi-crate workspace environment, the following error is produced:

> cargo check
    Checking leptos_i18n v0.2.1
error[E0428]: the name `fetch_locale` is defined multiple times
  -->$CARGO_DIR/registry/src/index.crates.io-6f17d22bba15001f/leptos_i18n-0.2.1/src/fetch_locale.rs:10:1
   |
5  | pub fn fetch_locale<T: Locale>() -> T {
   | ------------------------------------- previous definition of the value `fetch_locale` here
...
10 | pub fn fetch_locale<T: Locale>() -> T {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fetch_locale` redefined here
   |
   = note: `fetch_locale` must be defined only once in the value namespace of this module

For more information about this error, try `rustc --explain E0428`.

Steps To Reproduce

  1. Clone the Leptos Axum Workspace template: https://github.com/leptos-rs/start-axum-workspace
    Latest commit at time of raising: 62ed4424dcc37ca75bbe6b236ce6427bf9cce296
  2. Add leptos_i18n as a dependency of the shared app. Full app/Cargo.toml:
[package]
name = "app"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
leptos.workspace = true
leptos_meta.workspace = true
leptos_router.workspace = true
leptos_axum = { workspace = true, optional = true }

http.workspace = true
cfg-if.workspace = true
thiserror.workspace = true
leptos_i18n = { version = "0.2.1", default-features = false, features = [
    "json_files",
] }

[features]
default = []
hydrate = [
    "leptos/hydrate",
    "leptos_meta/hydrate",
    "leptos_router/hydrate",
    "leptos_i18n/hydrate",
]
ssr = [
    "leptos/ssr",
    "leptos_meta/ssr",
    "leptos_router/ssr",
    "leptos_i18n/axum",
    "dep:leptos_axum",
]
  1. Run cargo check against the workspace

Additional Information

This appears to be due to the way Cargo resolves features of shared dependencies: https://doc.rust-lang.org/cargo/reference/features.html#feature-unification. In this example above, both the frontend and server crates depend on app, but with different sets of features enabled. Cargo then assumes these features are additive, attempts to build app with both the hydrate and axum (ssr) features enabled, producing the original error.

Desired Outcome

The hydrate and ssr features can be enabled at the same time, and compile.

The following is a "functioning" version of src/fetch_locale.rs, but is relatively ugly and may have unintended consequences:

use crate::Locale;

#[cfg(all(feature = "ssr", not(feature = "hydrate")))]
#[inline]
pub fn fetch_locale<T: Locale>() -> T {
    crate::server::fetch_locale_server_side::<T>()
}

#[cfg(all(feature = "hydrate", not(feature = "ssr")))]
pub fn fetch_locale<T: Locale>() -> T {
    leptos::document()
        .document_element()
        .and_then(|el| el.get_attribute("lang"))
        .and_then(|lang| T::from_str(&lang))
        .unwrap_or_default()
}

#[cfg(any(
    all(feature = "hydrate", feature = "ssr"),
    not(any(
        feature = "ssr",
        feature = "hydrate",
        all(feature = "csr", feature = "cookie")
    ))
))]
#[inline]
pub fn fetch_locale<T: Locale>() -> T {
    Default::default()
}

#[cfg(all(feature = "csr", feature = "cookie"))]
pub fn fetch_locale<T: Locale>() -> T {
    fn inner<T: Locale>() -> Option<T> {
        let document = super::get_html_document()?;
        let cookies = document.cookie().ok()?;
        cookies.split(';').find_map(|cookie| {
            let (key, value) = cookie.split_once('=')?;
            if key.trim() == super::COOKIE_PREFERED_LANG {
                T::from_str(value)
            } else {
                None
            }
        })
    }
    inner().unwrap_or_default()
}

Remove `Into<N>` for plurals

First implementation of plurals took impl Fn() -> i64 + ... for the count, then evolved to impl Fn() -> Into<i64>, so when being able to select the type for count came out it moved again to impl Fn() -> Into<N> with N the type of count for the plural.

I'm not a big fan of implicit conversion, and this can lead to bad type inference, for exemple when you declare your plural to u32 but don't constrain your signal type and it default to i32, it will create an error stating that i32don't implement Into<u32>.

It would be better to take impl Fn() -> N directly.

i18n disables islands

Using use_i18n() in an island disables it, at least with Axum, no idea with Actix.

Reproduction is super easy: generate the default Axum SSR project, configure islands & i18n, call use_i18n() in the island and…nothing happens.

Here’s the console’s error:
image

Feature request: component with defaultValue and extract translations out of it

here is an example:

<Trans
  i18nKey="myKey" // optional -> fallbacks to defaults if not provided
  defaults="hello <italic>beautiful</italic> <bold>{{what}}</bold>" // optional defaultValue
  values={{ what: 'world'}}
  components={{ italic: <i />, bold: <strong /> }}
/>

Source: https://react.i18next.com/latest/trans-component

They extract the keys and the defaults value then writes to for example en.json, no need to edit that huge file after a while.

They also supply a function t where you can invoke for example t('my-key', { defaultValue: 'hello {{name}}', values: 'me' }, this is necessary since you might want to get a translation string outside a view component.

The whole point is to automatically extract translations with minimal effort avoiding the need to open, read and edit huge translation files.

Locales Cache (?) not updating

I am using actix and translations work fine for locales at first glance (in this example I am using EN & FR). However, when I update the values in the json files, the site does not update from the previous translations, even after rebuilding the project (or doing CTRL+Shift+R). The only way the translations update is if I change the key name in the json and within the rust implementation itself.

I have no idea why or how this is happening.

Any help would be appreciated.

I can provide any code that is needed.

Rework interpolation builders

For interpolations a builder is created, the current implementation works fine but there is two problems:

  • You can pass 2 times the same prop, this should at least give a warning because you are overriding a value without doing any work.
  • If a key is missing the error is terrible as the builder relies on generics to implement leptos::IntoView, so you don't know what key is missing, you don't even know that a key is missing.

First problem can either be done on expanded code with use of #[deprecated(note = "duplicated field foo"] when the field is already set, or by allowing to set the value only when T = EmptyInterpolateValue, or it can be done within the t! macro. First solution would be the better as a custom message can be created.

Second problem is going to be hard to implement, I'm not sure how to properly do it, the only way I see is to use a build method at the end that just serves as a check, but would have 2^N implementations, where 1 implementation would be with all values set, and the other with one or multiple values not set and use the deprecated attribute to give warning on what prop is missing, and panicking in the body with the same message (would return () to avoid compilation error where the returned value does not impl leptos::IntoView).

Those 2 changes would massively increase the size of outputed code, and even if most of it would be thrown away after compilation it would still impact compiling speed, maybe gate it behind a feature? or only debug mode? I don't known the impact on compiling speed when config gating things, I'm assuming the compiler can just throw it right away.

`load_locales!()` does not work with leptos `0.4.10`

Error:

error[E0061]: this function takes 2 arguments but 1 argument was supplied
src/lib.rs:1:1
leptos_i18n::load_locales!();
argument of type `leptos::Scope` is missing
note: method defined here
/home/xxx/.cargo/registry/src/index.crates.io-6f17d22bba15001f/leptos_dom-0.4.10/src/lib.rs:231:8231
fn collect_view(self, cx: Scope) -> View;
= note: this error originates in the macro `leptos_i18n::load_locales` (in Nightly builds, run with -Z macro-backtrace for more info)
help: provide the argument1   | 
leptos_i18n::load_locales!()(leptos_i18n::load_locales!(), /* leptos::Scope */);

yaml_files feature does not support .yml file extension

For some obscure or archaic reason (not trying to judge anyone here) some people still use .yml as file extension for their YAML files.

I think the "standard" or what is recommended is to use .yaml. but if you ever want to accomodate everyone, support for .yml should maybe be added.

Lazy loading of locale data

Is it possible to do lazy loading of locale data?
Locale data can be huge depending on the number of keys and languages, and usually only 1 language's values are needed at runtime.
So a lot can be saved by lazy loading (which is why e.g. i18next supports it).

Plurals fails to compile with duplicate `__var_count` generic

Been struggling to get this to compile in my project. I'm not sure if I'm just using this feature wrong, or if there's a bug in the implementation.

It seems to be caused when there is only one locale available.

Here's a minimal reproduction:

Cargo.toml

[dependencies]
leptos = { version = "0.5.0", features = ["csr"] }
leptos_meta = { version = "0.5.0", features = ["csr"] }
leptos_i18n = { path = "../../leptos_i18n", default-features = false, features = [
    "debug_interpolations",
    "csr",
    "cookie",
    "yaml_files",
] }
serde = { version = "1", features = ["derive"] }
console_error_panic_hook = { version = "0.1" }
wasm-bindgen = { version = "=0.2.87" }

[package.metadata.leptos-i18n]
default = "en"
locales = ["en"]

src/app.rs

#[component]
pub fn App() -> impl IntoView {
    leptos_meta::provide_meta_context();

    let i18n = provide_i18n_context();

    view! {
        <p>{t!(i18n, result_summary, count = || 5, query_str = || "test")}</p>
    }
}

locales/en.yaml

---
result_summary:
  - "u64"
  - ["No results for {{ query_str }}:", 0]
  - ["1 result for {{ query_str }}:", 1]
  - ["{{ count }} results for {{ query_str }}:"]
❯ trunk build
2023-10-27T22:24:07.047974Z  INFO 📦 starting build
2023-10-27T22:24:07.048390Z  INFO spawning asset pipelines
2023-10-27T22:24:07.160652Z  INFO building yaml
   Compiling yaml v0.1.0 (/Users/lpetherbridge/pdev/leptos_i18n/examples/yaml)
error[E0403]: the name `__var_count` is already used for a generic parameter in this item's generic parameters
 --> src/main.rs:4:1
  |
4 | leptos_i18n::load_locales!();
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  | |
  | already used
  | first use of `__var_count`
  |
  = note: this error originates in the macro `leptos_i18n::load_locales` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0416]: identifier `var_count` is bound more than once in the same pattern
 --> src/main.rs:4:1
  |
4 | leptos_i18n::load_locales!();
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ used in a pattern more than once

error[E0124]: field `var_count` is already declared
 --> src/main.rs:4:1
  |
4 | leptos_i18n::load_locales!();
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  | |
  | field already declared
  | `var_count` first declared here
  |
  = note: this error originates in the macro `leptos_i18n::load_locales` (in Nightly builds, run with -Z macro-backtrace for more info)

Some errors have detailed explanations: E0124, E0403, E0416.
For more information about an error, try `rustc --explain E0124`.
error: could not compile `yaml` (bin "yaml") due to 3 previous errors

Recompile on changed locale files

Is there a way to get cargo leptos watch to recompile the lib (load_locales!) when files in the locales directory change?

I tried watch-additional-files = ["locales"] in Cargo.toml but cargo doesn't think that anything in the lib has changed so just links.

Support for subkeys

Someone suggested support for subkeys without namespacing, that would mean supporting this structure:

{
    "primary_key": {
        "sub_key_1": "this is a subkey",
        "sub_key_2": "this is another subkey",
    }
}

with

t!(i18n, primary_key.sub_key_1)

This won't be that much difficult to implement but would break the current structure for plurals

My proposal would be to migrate plurals from a map to a sequence, which would make also more sense as plurals are order dependents and rely on serde_json being a "lazy" parser and keeping the order.

So plurals would go from

{
  "click_count": {
    "0": "You have not clicked yet",
    "1": "You clicked once",
    "_": "You clicked {{ count }} times"
  }
}

to

{
  "click_count": [
      ["0", "You have not clicked yet"],
      ["1", "You clicked once"],
      ["_", "You clicked {{ count }} times"]
   ]
}

This would be one way to do it, any suggestions are welcome.

As this is a breaking change it would come with v0.2.0 (if ready by then).

Make `td!` behavior similar to `t!`

Curently t!(i18n, ..) is basically move || td!(i18n.get_locale(), ..), the reason td! is not wrapped in a closure is because it was a way to access the underlying &str for a given locale.

Now that td_string! and td_display! exists they offer both access to the &str with more meaning in the name of the macro, most users that want static access to the &str would use td_string! or td_display!, so this leave td! in a weird spot that makes it being almost exclusively used with move || td!(locale, ..).

td! should behave the same way as t!, this would be a breaking change though.

Add routes for each locales

For now the locale is just set as a cookie (if feature enabled) or retrieved from the client request, but it would be great to also insert the locale in the URL:

  • when default: domain/path
  • when not default: domain/locale/path

I will if this is possible and how to implement that.

Add `csr` support

I have not tested if this crate works with csr, but the only backend/hydratation related operations are retrieving what locale to use.
If neither hydrate or actix/axum features are enabled, it's always the default locale that is selected.
So csr should work but the cookie feature is'nt used by csr, adding a csr feature that check the cookies for the the locale would be all that need to be done (I think ?).

Leptos warning ' .. outside reactive context ... ' when running

Hi,

thx for the crate, it works pretty fine.

During the execution (I use V0.3.0-rc) I get in the console the following warning from Leptos

At /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/leptos_i18n-0.3.0-rc/src/context.rs:18:16, you access a signal or memo (defined at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/leptos_i18n-0.3.0-rc/src/context.rs:67:18) outside a reactive tracking context. This might mean your app is not responding to changes in signal values in the way you expect.

Here’s how to fix it:

1. If this is inside a `view!` macro, make sure you are passing a function, not a value.
  ❌ NO  <p>{x.get() * 2}</p>
  ✅ YES <p>{move || x.get() * 2}</p>

2. If it’s in the body of a component, try wrapping this access in a closure: 
  ❌ NO  let y = x.get() * 2
  ✅ YES let y = move || x.get() * 2.

3. If you’re *trying* to access the value without tracking, use `.get_untracked()` or `.with_untracked()` instead.

You maybe find some time to take a look at it, I tried with exchanging

#[inline]
pub fn get_locale(self) -> T {
    self.0.get()
}

with

#[inline]
pub fn get_locale(self) -> T {
    (move || self.0.get())()
}

Which was not succesful.

unable to render valid html string

this one fails:

<article><h2>Effortless Process: From Virtual Introduction to Contract with Our Talent Partner</h2><p>Our talent partner simplifies your recruitment journey for maximum efficiency, whether you're seeking candidates for hybrid, remote, or onsite positions. Our adaptable approach ensures you're informed every step of the way, encompassing permanent positions, headhunting, and contract limited time roles. Here's a detailed look at our process, including virtual meetings, contract signing, fee details, and the one-time replacement guarantee:<h3>1. Schedule Virtual Meeting Invite</h3><p>To kickstart our collaboration, schedule a virtual meeting invite. During this meeting, we'll discuss your recruitment needs, spanning hybrid, remote, or onsite positions, including permanent roles, headhunting, and contract limited time opportunities. This initial step sets the stage for our partnership.<h3>2. Understanding Our Versatile Approach</h3><p>Our recruitment model encompasses various options to suit your hiring requirements:<ul><li><strong>Contingency Hiring:</strong> This model is based on contingency, meaning we only generate revenue upon successfully placing an employee with you. Until that point, we don't charge any fees. The fees charged are influenced by various factors, including the complexity of the role, candidate's first-year salary, and adherence to relevant regulations. On average, typical recruitment fees range from 15% to 25% of the candidate's first-year salary.<li><strong>Retainer Model:</strong> Alternatively, we accept retainer model agreements. With this option, companies pay an upfront fee to create an exclusive contract for the recruitment process. This approach allows for greater dedication and personalized attention to your needs. Part of the fee is paid upfront, demonstrating commitment and enabling us to initiate the process promptly. The remaining payment is made at varying points of the process. Despite the variation, the total percentage paid remains within the range of 15% to 25% of the candidate's first-year salary.<li><strong>Contract Placement:</strong> For contract placements, we provide an internal payroll solution. We handle the employee's payroll and charge the client based on a comprehensive fee structure. This fee includes the employee's wages along with an additional amount to cover expenses. Typically, this fee equates to around 1.5 times the employee's wages. For instance, if an employee earns $20 per hour, the agency would charge the client $20 times 1.5, resulting in a rate of $30 per hour. Contract placements often pave the way for potential temp-to-Hire roles.</ul><p><strong>Guarantee and Refund Policy:</strong> Our one-time replacement guarantee ensures your satisfaction. If a candidate doesn't meet your expectations within the agreed period, we offer a replacement candidate. The guarantee covers a single replacement, and any additional terms will be outlined in the agreement. This policy is open to negotiation, ensuring that your unique needs are met.<p>Following our detailed discussion, we'll tailor agreements that encapsulate the fee structure, guarantee terms, and the chosen recruitment model, including our negotiable guarantee and refund policy. Rest assured, our process ensures compliance with regulations and dedication to your unique recruitment needs.<h3>3. Diligent Search</h3><p>Our search commences, leveraging our extensive network and expertise to identify ideal candidates.<h3>4. Candidate-Employer Match and Multiple Choices</h3><p>We meticulously evaluate candidates to ensure a seamless alignment with your criteria and company culture. In situations where you present multiple candidates, our evaluation extends to all choices.<h3>5. Candidate Interview Process and Contract Preparation</h3><p>As candidates are chosen continuously, this step continues until you find a candidate you like. We facilitate the interview scheduling process with your team. Our goal is to ensure seamless communication and coordination between the candidates and your employees, culminating in a successful mutual agreement. Following the successful interviews, comprehensive contracts are prepared for both parties involved.<h3>6. Collaboration for Agreement</h3><p>Contracts are shared for review, emphasizing open lines of communication. Once both the candidate and your team agree, the contracts are officially executed, solidifying the agreement.<h3>7. Payment After Placement - Invoice Sent Upon Start</h3><p>Following the candidate's start date, an invoice will be promptly sent to your organization for payment. This invoice corresponds to the agreed-upon fee structure as outlined in the agreement. The payment is due within 14 days from the candidate's start date.<h3>9. Continuing Partnership</h3><p>Our dedication endures past placement. We ensure a smooth transition and nurture lasting relationships.<p>Our process ensures you're informed, from scheduling a virtual meeting invite to candidate placement across various positions. The adaptable fee structure, aligned with your chosen recruitment model, intrinsically tied to the complexity of the role and the candidate's first-year salary, reflects our dedication to streamlining your hiring process.<p>Experience recruitment ease with our talent partner. With the added assurance of our one-time replacement guarantee and compliance with relevant regulations, we're steadfastly with you at every step.</article>
error[E0599]: no method named `comp_h3` found for struct `__page_home_section_process_content_builder` in the current scope
  --> src/components/home/section_process.rs:21:10
   |
16 |         {i18n::t!(
   |  ________-
17 | |         i18n,
18 | |         page_home_section_process_content,
19 | |         <article> = |cx, children| view!{ cx, <article class=format!("col-xs-12 {}", ClassName::CONTENT)>{chil...
20 | |         <h2> = |cx, children| view!{ cx, <h2>{children(cx)}</h2> },
21 | |         <h3> = |cx, children| view!{ cx, <h3>{children(cx)}</h3> },
   | |         -^^ help: there is a method with a similar name: `comp_h2

It's minified and verified valid HTML.

The rust code used:

     {i18n::t!(
        i18n,
        page_home_section_process_content,
        <article> = |cx, children| view!{ cx, <article class=format!("col-xs-12 {}", ClassName::CONTENT)>{children(cx)}</article> },
        <h2> = |cx, children| view!{ cx, <h2>{children(cx)}</h2> },
        <h3> = |cx, children| view!{ cx, <h3>{children(cx)}</h3> },
        <p> = |cx, children| view!{ cx, <p>{children(cx)}</p> },
        <strong> = |cx, children| view!{ cx, <strong>{children(cx)}</strong> },
        <ul> = |cx, children| view!{ cx, <ul>{children(cx)}</ul> },
        <li> = |cx, children| view!{ cx, <li>{children(cx)}</li> }
      )}

Yaml support

Hi,

Just leaving this here, I know it is most likely a big endeavour. But would you be open to support yaml file for the translations? I am not asking to replace json, as some people might prefer that, but maybe a way to support both a bit like rust-i18n does?

It's far from important or anything, json works just fine, just a personal preference on my end. :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.