Repository: zng-ui/zng (language: rust)

Issue:
`l10n!` interpolation does not support non variables
<!--
Please, make sure:

- The issue happens in the latest crate release or newer (master branch).
- The issue happens after `cargo update`.
-->

#### I tried this code:

```rust
let _l = l10n!("some-key", "Foo is {$foo}!", foo=Txt::from("bar!"));
```

#### I saw this happen:

Build error.

#### I expected this to happen:

Text interpolation.

#### Error log or stack trace:

<details>
  <summary>stderr</summary>

```
error[E0507]: cannot move out of a shared reference

move occurs because value has type `zng_ext_l10n::types::L10nSpecialize<zng::text::Txt>`, 
which does not implement the `Copy` trait
```

</details>


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c303b1c44..4f50a3b9f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
 # Unpublished
 
+* Fix `l10n!` interpolation of non-var values.
 * Allow missing authors field in `zng_env::About::parse_manifest`.
 * Fix `cargo zng res` not finding any metadata.
 
diff --git a/crates/zng-ext-l10n-proc-macros/src/l10n.rs b/crates/zng-ext-l10n-proc-macros/src/l10n.rs
index 16d330828..0100f6fa9 100644
--- a/crates/zng-ext-l10n-proc-macros/src/l10n.rs
+++ b/crates/zng-ext-l10n-proc-macros/src/l10n.rs
@@ -92,7 +92,7 @@ pub fn expand(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
             build.extend(quote_spanned! {span=>
                 .l10n_arg(#var, {
                     use #l10n_path::IntoL10nVar;
-                    (&&#l10n_path::L10nSpecialize(#var_ident)).into_l10n_var()
+                    (&mut &mut #l10n_path::L10nSpecialize(Some(#var_ident))).to_l10n_var()
                 })
             });
         }
diff --git a/crates/zng-ext-l10n/src/types.rs b/crates/zng-ext-l10n/src/types.rs
index da07a1cae..8267a8114 100644
--- a/crates/zng-ext-l10n/src/types.rs
+++ b/crates/zng-ext-l10n/src/types.rs
@@ -243,32 +243,32 @@ impl L10nArgument {
 }
 
 #[doc(hidden)]
-pub struct L10nSpecialize<T>(pub T);
+pub struct L10nSpecialize<T>(pub Option<T>);
 #[doc(hidden)]
 pub trait IntoL10nVar {
     type Var: Var<L10nArgument>;
-    fn into_l10n_var(self) -> Self::Var;
+    fn to_l10n_var(&mut self) -> Self::Var;
 }
 
 impl<T: Into<L10nArgument>> IntoL10nVar for L10nSpecialize<T> {
     type Var = LocalVar<L10nArgument>;
 
-    fn into_l10n_var(self) -> Self::Var {
-        LocalVar(self.0.into())
+    fn to_l10n_var(&mut self) -> Self::Var {
+        LocalVar(self.0.take().unwrap().into())
     }
 }
-impl<T: VarValue + Into<L10nArgument>> IntoL10nVar for &L10nSpecialize<ArcVar<T>> {
+impl<T: VarValue + Into<L10nArgument>> IntoL10nVar for &mut L10nSpecialize<ArcVar<T>> {
     type Var = ReadOnlyArcVar<L10nArgument>;
 
-    fn into_l10n_var(self) -> Self::Var {
-        self.0.map_into()
+    fn to_l10n_var(&mut self) -> Self::Var {
+        self.0.take().unwrap().map_into()
     }
 }
-impl<V: Var<L10nArgument>> IntoL10nVar for &&L10nSpecialize<V> {
+impl<V: Var<L10nArgument>> IntoL10nVar for &mut &mut L10nSpecialize<V> {
     type Var = V;
 
-    fn into_l10n_var(self) -> Self::Var {
-        self.0.clone()
+    fn to_l10n_var(&mut self) -> Self::Var {
+        self.0.take().unwrap()
     }
 }
 


Test patch: