From 0fdcc91a10de226a125e83fd212afd65dacafcda Mon Sep 17 00:00:00 2001 From: iatsenko <1586852+timofei-iatsenko@users.noreply.github.com> Date: Tue, 14 Apr 2026 14:49:28 +0200 Subject: [PATCH 1/6] feat!: Consolidate Metadata Transformation Options into descriptorFields --- README.md | 18 ++- src/js_macro_folder.rs | 27 +++-- src/lib.rs | 23 ++-- src/options.rs | 112 +++++++++++++++--- ...rops.js => id_only_should_keep_only_id.js} | 0 ...message_should_keep_message_and_context.js | 12 ++ ...s.js => js_id_only_should_keep_only_id.js} | 0 ...message_should_keep_message_and_context.js | 13 ++ ...js => id_only_essential_props_are_kept.js} | 0 .../jsx.rs/jsx_preserve_reserved_attrs.js | 3 +- .../message_keeps_message_and_context.js | 12 ++ ...js => id_only_essential_props_are_kept.js} | 0 .../jsx_plural_preserve_reserved_attrs.js | 3 +- .../jsx_select_with_reserved_attrs.js | 3 +- .../message_keeps_message_and_context.js | 12 ++ tests/js_define_message.rs | 24 +++- tests/js_t.rs | 24 +++- tests/jsx.rs | 23 +++- tests/jsx_icu.rs | 29 ++++- 19 files changed, 284 insertions(+), 54 deletions(-) rename tests/__swc_snapshots__/tests/js_define_message.rs/{should_kept_only_essential_props.js => id_only_should_keep_only_id.js} (100%) create mode 100644 tests/__swc_snapshots__/tests/js_define_message.rs/message_should_keep_message_and_context.js rename tests/__swc_snapshots__/tests/js_t.rs/{js_should_kept_only_essential_props.js => js_id_only_should_keep_only_id.js} (100%) create mode 100644 tests/__swc_snapshots__/tests/js_t.rs/js_message_should_keep_message_and_context.js rename tests/__swc_snapshots__/tests/jsx.rs/{production_only_essential_props_are_kept.js => id_only_essential_props_are_kept.js} (100%) create mode 100644 tests/__swc_snapshots__/tests/jsx.rs/message_keeps_message_and_context.js rename tests/__swc_snapshots__/tests/jsx_icu.rs/{production_only_essential_props_are_kept.js => id_only_essential_props_are_kept.js} (100%) create mode 100644 tests/__swc_snapshots__/tests/jsx_icu.rs/message_keeps_message_and_context.js diff --git a/README.md b/README.md index e083534..53ef221 100644 --- a/README.md +++ b/README.md @@ -50,10 +50,9 @@ https://swc.rs/docs/configuration/swcrc // "i18n": ["@lingui/core", "i18n"], // "trans": ["@lingui/react", "Trans"] // } - // Lingui strips non-essential fields in production builds for performance. - // Docs https://lingui.dev/guides/optimizing-bundle-size - // You can override the default behavior with: - // "stripNonEssentialFields": false/true + // + // Optional. Controls which descriptor fields are preserved in output. + // "descriptorFields": "auto" (default) | "all" | "id-only" | "message" // Compatibility option allows to use v6.* SWC Plugin release channel with @lingui/cli@5.* // Controls the BASE64 alphabet used for generating message IDs. @@ -70,6 +69,17 @@ https://swc.rs/docs/configuration/swcrc } ``` +### `descriptorFields` + +Controls which fields are preserved in the transformed message descriptors. Accepts one of: + +- **`"auto"`** (default) — In production (`NODE_ENV=production`), behaves like `"id-only"`. Otherwise, behaves like `"all"`. +- **`"all"`** — Keeps `id`, `message`, `context`, and `comment`. Use this for extraction (replaces the old `extract: true` from the Babel plugin). +- **`"id-only"`** — Keeps only the `id`. Most optimized for production bundles. +- **`"message"`** — Keeps `id`, `message`, and `context` (but not `comment`). Useful when you need message content at runtime. + +Check [this article](https://lingui.dev/guides/optimizing-bundle-size) for more info about this configuration. + Or Next JS Usage: `next.config.js` diff --git a/src/js_macro_folder.rs b/src/js_macro_folder.rs index 99f31dd..c09354b 100644 --- a/src/js_macro_folder.rs +++ b/src/js_macro_folder.rs @@ -43,7 +43,7 @@ where .into(), )]; - if !self.ctx.options.strip_non_essential_fields { + if self.ctx.options.descriptor_fields.should_keep_message() { props.push(create_key_value_prop("message", parsed.message)); } @@ -104,8 +104,10 @@ where if let Expr::Object(obj) = *expr { let id_prop = get_object_prop(&obj.props, "id"); - let context_val = get_object_prop(&obj.props, "context") - .and_then(|prop| get_expr_as_string(&prop.value)); + let context_prop = get_object_prop(&obj.props, "context"); + let context_val = context_prop.and_then(|prop| get_expr_as_string(&prop.value)); + + let comment_prop = get_object_prop(&obj.props, "comment"); let message_prop = get_object_prop(&obj.props, "message"); @@ -134,7 +136,7 @@ where )) } - if !self.ctx.options.strip_non_essential_fields { + if self.ctx.options.descriptor_fields.should_keep_message() { new_props.push(create_key_value_prop("message", parsed.message)); } @@ -143,16 +145,17 @@ where } } - if !self.ctx.options.strip_non_essential_fields { - if let Some(context) = context_val { - new_props.push(create_key_value_prop("context", context.into())); + if self.ctx.options.descriptor_fields.should_keep_context() { + if let Some(context_str) = &context_val { + new_props.push(create_key_value_prop("context", context_str.clone().into())); } + } - let comment = get_object_prop(&obj.props, "comment") - .and_then(|prop| get_expr_as_string(&prop.value)); - - if let Some(comment) = comment { - new_props.push(create_key_value_prop("comment", comment.into())); + if self.ctx.options.descriptor_fields.should_keep_comment() { + if let Some(prop) = comment_prop { + if let Some(value) = get_expr_as_string(&prop.value) { + new_props.push(create_key_value_prop("comment", value.into())); + } } } diff --git a/src/lib.rs b/src/lib.rs index cbc4fd9..e05783f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -152,17 +152,24 @@ where message_descriptor_props.push(create_key_value_prop("components", exp)); } - if !self.ctx.options.strip_non_essential_fields { - let comment_attr = get_jsx_attr(&el.opening, "comment") - .and_then(|attr| attr.value.as_ref()) - .and_then(get_jsx_attr_value_as_string); + if self.ctx.options.descriptor_fields.should_keep_comment() { + let comment_attr = + get_jsx_attr(&el.opening, "comment").and_then(|attr| attr.value.as_ref()); - if let Some(comment) = comment_attr { - message_descriptor_props.push(create_key_value_prop("comment", comment.into())); + if let Some(comment_attr) = comment_attr { + let comment_attr_val = get_jsx_attr_value_as_string(comment_attr).unwrap(); + + message_descriptor_props.push(create_key_value_prop( + "comment", comment.into(), + )); } + } + if self.ctx.options.descriptor_fields.should_keep_message() { message_descriptor_props.push(create_key_value_prop("message", parsed.message)); + } + if self.ctx.options.descriptor_fields.should_keep_context() { if let Some(context_attr) = context_attr { let context_attr_val = get_jsx_attr_value_as_string(context_attr).unwrap(); @@ -177,6 +184,8 @@ where } } + + let message_descriptor = Expr::Object(ObjectLit { span: message_dscrptr_span, props: message_descriptor_props, @@ -515,7 +524,7 @@ where } } -pub use self::options::{LinguiOptions, RuntimeModulesConfigMapNormalized}; +pub use self::options::{DescriptorFields, LinguiOptions, RuntimeModulesConfigMapNormalized}; #[plugin_transform] pub fn process_transform(program: Program, metadata: TransformPluginProgramMetadata) -> Program { diff --git a/src/options.rs b/src/options.rs index 2c557ac..5bec04f 100644 --- a/src/options.rs +++ b/src/options.rs @@ -1,11 +1,34 @@ use serde::Deserialize; +#[derive(Deserialize, Debug, PartialEq, Clone)] +#[serde(rename_all = "kebab-case")] +pub enum DescriptorFields { + Auto, + All, + IdOnly, + Message, +} + +impl DescriptorFields { + pub fn should_keep_message(&self) -> bool { + matches!(self, DescriptorFields::All | DescriptorFields::Message) + } + + pub fn should_keep_context(&self) -> bool { + matches!(self, DescriptorFields::All | DescriptorFields::Message) + } + + pub fn should_keep_comment(&self) -> bool { + matches!(self, DescriptorFields::All) + } +} + #[derive(Deserialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct LinguiJsOptions { runtime_modules: Option, #[serde(default)] - strip_non_essential_fields: Option, + descriptor_fields: Option, #[serde(default)] use_lingui_v5_id_generation: Option, } @@ -30,10 +53,19 @@ pub struct RuntimeModulesConfigMapNormalized { impl LinguiJsOptions { pub fn into_options(self, env_name: &str) -> LinguiOptions { + let descriptor_fields = match self.descriptor_fields.unwrap_or(DescriptorFields::Auto) { + DescriptorFields::Auto => { + if matches!(env_name, "production") { + DescriptorFields::IdOnly + } else { + DescriptorFields::All + } + } + other => other, + }; + LinguiOptions { - strip_non_essential_fields: self - .strip_non_essential_fields - .unwrap_or(matches!(env_name, "production")), + descriptor_fields, use_lingui_v5_id_generation: self.use_lingui_v5_id_generation.unwrap_or(false), runtime_modules: RuntimeModulesConfigMapNormalized { i18n: ( @@ -79,7 +111,7 @@ impl LinguiJsOptions { #[derive(Debug, Clone)] pub struct LinguiOptions { - pub strip_non_essential_fields: bool, + pub descriptor_fields: DescriptorFields, pub runtime_modules: RuntimeModulesConfigMapNormalized, pub use_lingui_v5_id_generation: bool, } @@ -87,7 +119,7 @@ pub struct LinguiOptions { impl Default for LinguiOptions { fn default() -> LinguiOptions { LinguiOptions { - strip_non_essential_fields: false, + descriptor_fields: DescriptorFields::All, use_lingui_v5_id_generation: false, runtime_modules: RuntimeModulesConfigMapNormalized { i18n: ("@lingui/core".into(), "i18n".into()), @@ -132,7 +164,7 @@ mod lib_tests { Some("myUseLingui".into()) )), }), - strip_non_essential_fields: None, + descriptor_fields: None, use_lingui_v5_id_generation: None, } ) @@ -157,58 +189,106 @@ mod lib_tests { trans: None, use_lingui: None, }), - strip_non_essential_fields: None, + descriptor_fields: None, use_lingui_v5_id_generation: None, } ) } #[test] - fn test_strip_non_essential_fields_config() { + fn test_descriptor_fields_config() { + let config = serde_json::from_str::( + r#"{ + "descriptorFields": "id-only", + "runtimeModules": {} + }"#, + ) + .unwrap(); + + let options = config.into_options("development"); + assert!(matches!( + options.descriptor_fields, + DescriptorFields::IdOnly + )); + + let config = serde_json::from_str::( + r#"{ + "descriptorFields": "all", + "runtimeModules": {} + }"#, + ) + .unwrap(); + + let options = config.into_options("production"); + assert!(matches!(options.descriptor_fields, DescriptorFields::All)); + + let config = serde_json::from_str::( + r#"{ + "descriptorFields": "message", + "runtimeModules": {} + }"#, + ) + .unwrap(); + + let options = config.into_options("production"); + assert!(matches!( + options.descriptor_fields, + DescriptorFields::Message + )); + } + + #[test] + fn test_descriptor_fields_auto_default() { let config = serde_json::from_str::( r#"{ - "stripNonEssentialFields": true, "runtimeModules": {} }"#, ) .unwrap(); let options = config.into_options("development"); - assert!(options.strip_non_essential_fields); + assert!(matches!(options.descriptor_fields, DescriptorFields::All)); let config = serde_json::from_str::( r#"{ - "stripNonEssentialFields": false, "runtimeModules": {} }"#, ) .unwrap(); let options = config.into_options("production"); - assert!(!options.strip_non_essential_fields); + assert!(matches!( + options.descriptor_fields, + DescriptorFields::IdOnly + )); } #[test] - fn test_strip_non_essential_fields_default() { + fn test_descriptor_fields_explicit_auto() { let config = serde_json::from_str::( r#"{ + "descriptorFields": "auto", "runtimeModules": {} }"#, ) .unwrap(); let options = config.into_options("development"); - assert!(!options.strip_non_essential_fields); + assert!(matches!(options.descriptor_fields, DescriptorFields::All)); let config = serde_json::from_str::( r#"{ + "descriptorFields": "auto", "runtimeModules": {} }"#, ) .unwrap(); let options = config.into_options("production"); - assert!(options.strip_non_essential_fields); + assert!(matches!( + options.descriptor_fields, + DescriptorFields::IdOnly + )); } #[test] diff --git a/tests/__swc_snapshots__/tests/js_define_message.rs/should_kept_only_essential_props.js b/tests/__swc_snapshots__/tests/js_define_message.rs/id_only_should_keep_only_id.js similarity index 100% rename from tests/__swc_snapshots__/tests/js_define_message.rs/should_kept_only_essential_props.js rename to tests/__swc_snapshots__/tests/js_define_message.rs/id_only_should_keep_only_id.js diff --git a/tests/__swc_snapshots__/tests/js_define_message.rs/message_should_keep_message_and_context.js b/tests/__swc_snapshots__/tests/js_define_message.rs/message_should_keep_message_and_context.js new file mode 100644 index 0000000..58417c9 --- /dev/null +++ b/tests/__swc_snapshots__/tests/js_define_message.rs/message_should_keep_message_and_context.js @@ -0,0 +1,12 @@ +const message1 = /*i18n*/ { + id: "xDAtGP", + message: "Message" +}; +const message2 = /*i18n*/ { + id: "msgId", + message: "Hello {name}", + values: { + name: name + }, + context: "My Context" +}; diff --git a/tests/__swc_snapshots__/tests/js_t.rs/js_should_kept_only_essential_props.js b/tests/__swc_snapshots__/tests/js_t.rs/js_id_only_should_keep_only_id.js similarity index 100% rename from tests/__swc_snapshots__/tests/js_t.rs/js_should_kept_only_essential_props.js rename to tests/__swc_snapshots__/tests/js_t.rs/js_id_only_should_keep_only_id.js diff --git a/tests/__swc_snapshots__/tests/js_t.rs/js_message_should_keep_message_and_context.js b/tests/__swc_snapshots__/tests/js_t.rs/js_message_should_keep_message_and_context.js new file mode 100644 index 0000000..f143b93 --- /dev/null +++ b/tests/__swc_snapshots__/tests/js_t.rs/js_message_should_keep_message_and_context.js @@ -0,0 +1,13 @@ +import { i18n as $_i18n } from "@lingui/core"; +const msg1 = $_i18n._(/*i18n*/ { + id: "xDAtGP", + message: "Message" +}); +const msg2 = $_i18n._(/*i18n*/ { + id: "msgId", + message: "Hello {name}", + values: { + name: name + }, + context: "My Context" +}); diff --git a/tests/__swc_snapshots__/tests/jsx.rs/production_only_essential_props_are_kept.js b/tests/__swc_snapshots__/tests/jsx.rs/id_only_essential_props_are_kept.js similarity index 100% rename from tests/__swc_snapshots__/tests/jsx.rs/production_only_essential_props_are_kept.js rename to tests/__swc_snapshots__/tests/jsx.rs/id_only_essential_props_are_kept.js diff --git a/tests/__swc_snapshots__/tests/jsx.rs/jsx_preserve_reserved_attrs.js b/tests/__swc_snapshots__/tests/jsx.rs/jsx_preserve_reserved_attrs.js index 4cffe76..ec04671 100644 --- a/tests/__swc_snapshots__/tests/jsx.rs/jsx_preserve_reserved_attrs.js +++ b/tests/__swc_snapshots__/tests/jsx.rs/jsx_preserve_reserved_attrs.js @@ -3,5 +3,6 @@ const exp2 =
{p.translation}
} render={(v)=>v}/>; diff --git a/tests/__swc_snapshots__/tests/jsx.rs/message_keeps_message_and_context.js b/tests/__swc_snapshots__/tests/jsx.rs/message_keeps_message_and_context.js new file mode 100644 index 0000000..b29a2fb --- /dev/null +++ b/tests/__swc_snapshots__/tests/jsx.rs/message_keeps_message_and_context.js @@ -0,0 +1,12 @@ +import { Trans as Trans_ } from "@lingui/react"; + + }, + message: "Hello <0>{name}", + context: "My Context" +}} render="render" i18n="i18n"/>; diff --git a/tests/__swc_snapshots__/tests/jsx_icu.rs/production_only_essential_props_are_kept.js b/tests/__swc_snapshots__/tests/jsx_icu.rs/id_only_essential_props_are_kept.js similarity index 100% rename from tests/__swc_snapshots__/tests/jsx_icu.rs/production_only_essential_props_are_kept.js rename to tests/__swc_snapshots__/tests/jsx_icu.rs/id_only_essential_props_are_kept.js diff --git a/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_plural_preserve_reserved_attrs.js b/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_plural_preserve_reserved_attrs.js index 7546026..13ce5c2 100644 --- a/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_plural_preserve_reserved_attrs.js +++ b/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_plural_preserve_reserved_attrs.js @@ -6,5 +6,6 @@ import { Trans as Trans_ } from "@lingui/react"; }, comment: "Translators Comment", message: "{count, plural, one {...} other {...}}", - context: "Message Context" + context: "Message Context", + comment: "Translators Comment" }} render={(v)=>v}/>; diff --git a/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_select_with_reserved_attrs.js b/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_select_with_reserved_attrs.js index dab5412..78dfe75 100644 --- a/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_select_with_reserved_attrs.js +++ b/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_select_with_reserved_attrs.js @@ -9,5 +9,6 @@ import { Trans as Trans_ } from "@lingui/react"; }, comment: "Translators Comment", message: "{count, select, male {He} female {She} other {<0>Other}}", - context: "Message Context" + context: "Message Context", + comment: "Translators Comment" }} render={(v)=>v}/>; diff --git a/tests/__swc_snapshots__/tests/jsx_icu.rs/message_keeps_message_and_context.js b/tests/__swc_snapshots__/tests/jsx_icu.rs/message_keeps_message_and_context.js new file mode 100644 index 0000000..8f51431 --- /dev/null +++ b/tests/__swc_snapshots__/tests/jsx_icu.rs/message_keeps_message_and_context.js @@ -0,0 +1,12 @@ +import { Trans as Trans_ } from "@lingui/react"; + + }, + message: "{count, plural, offset:1 =0 {Zero items} other {<0>A lot of them}}", + context: "My Context" +}} render="render" i18n="i18n"/>; diff --git a/tests/js_define_message.rs b/tests/js_define_message.rs index 050b0b1..7e9de57 100644 --- a/tests/js_define_message.rs +++ b/tests/js_define_message.rs @@ -1,4 +1,4 @@ -use lingui_macro_plugin::LinguiOptions; +use lingui_macro_plugin::{DescriptorFields, LinguiOptions}; #[macro_use] mod common; @@ -61,9 +61,27 @@ to!( ); to!( - should_kept_only_essential_props, + id_only_should_keep_only_id, LinguiOptions { - strip_non_essential_fields: true, + descriptor_fields: DescriptorFields::IdOnly, + ..Default::default() + }, + r#" + import { defineMessage } from '@lingui/macro' + const message1 = defineMessage`Message`; + const message2 = defineMessage({ + message: `Hello ${name}`, + id: 'msgId', + comment: 'description for translators', + context: 'My Context', + }) + "# +); + +to!( + message_should_keep_message_and_context, + LinguiOptions { + descriptor_fields: DescriptorFields::Message, ..Default::default() }, r#" diff --git a/tests/js_t.rs b/tests/js_t.rs index f6e799c..4050e92 100644 --- a/tests/js_t.rs +++ b/tests/js_t.rs @@ -1,4 +1,4 @@ -use lingui_macro_plugin::LinguiOptions; +use lingui_macro_plugin::{DescriptorFields, LinguiOptions}; #[macro_use] mod common; @@ -146,9 +146,27 @@ to!( ); to!( - js_should_kept_only_essential_props, + js_id_only_should_keep_only_id, LinguiOptions { - strip_non_essential_fields: true, + descriptor_fields: DescriptorFields::IdOnly, + ..Default::default() + }, + r#" + import { t } from '@lingui/core/macro' + const msg1 = t`Message` + const msg2 = t({ + message: `Hello ${name}`, + id: 'msgId', + comment: 'description for translators', + context: 'My Context', + }) + "# +); + +to!( + js_message_should_keep_message_and_context, + LinguiOptions { + descriptor_fields: DescriptorFields::Message, ..Default::default() }, r#" diff --git a/tests/jsx.rs b/tests/jsx.rs index f8e8d30..cb416df 100644 --- a/tests/jsx.rs +++ b/tests/jsx.rs @@ -1,4 +1,4 @@ -use lingui_macro_plugin::LinguiOptions; +use lingui_macro_plugin::{DescriptorFields, LinguiOptions}; #[macro_use] mod common; @@ -283,9 +283,26 @@ to!( ); to!( - production_only_essential_props_are_kept, + id_only_essential_props_are_kept, LinguiOptions { - strip_non_essential_fields: true, + descriptor_fields: DescriptorFields::IdOnly, + ..Default::default() + }, + r#" + import { Trans } from "@lingui/react/macro"; + Hello {name} + "# +); + +to!( + message_keeps_message_and_context, + LinguiOptions { + descriptor_fields: DescriptorFields::Message, ..Default::default() }, r#" diff --git a/tests/jsx_icu.rs b/tests/jsx_icu.rs index e04d521..5dd4085 100644 --- a/tests/jsx_icu.rs +++ b/tests/jsx_icu.rs @@ -1,4 +1,4 @@ -use lingui_macro_plugin::LinguiOptions; +use lingui_macro_plugin::{DescriptorFields, LinguiOptions}; #[macro_use] mod common; @@ -210,9 +210,32 @@ to!( ); to!( - production_only_essential_props_are_kept, + id_only_essential_props_are_kept, LinguiOptions { - strip_non_essential_fields: true, + descriptor_fields: DescriptorFields::IdOnly, + ..Default::default() + }, + r#" + import { Plural } from '@lingui/macro'; + + A lot of them} + /> + "# +); + +to!( + message_keeps_message_and_context, + LinguiOptions { + descriptor_fields: DescriptorFields::Message, ..Default::default() }, r#" From 3909c416fdfb95243ca25915044098b618ec9786 Mon Sep 17 00:00:00 2001 From: iatsenko <1586852+timofei-iatsenko@users.noreply.github.com> Date: Tue, 14 Apr 2026 15:19:24 +0200 Subject: [PATCH 2/6] fix --- src/lib.rs | 7 ++----- .../tests/jsx.rs/jsx_preserve_reserved_attrs.js | 3 +-- .../tests/jsx_icu.rs/jsx_plural_preserve_reserved_attrs.js | 3 +-- .../tests/jsx_icu.rs/jsx_select_with_reserved_attrs.js | 3 +-- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e05783f..4c130bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -159,9 +159,8 @@ where if let Some(comment_attr) = comment_attr { let comment_attr_val = get_jsx_attr_value_as_string(comment_attr).unwrap(); - message_descriptor_props.push(create_key_value_prop( - "comment", comment.into(), - )); + message_descriptor_props + .push(create_key_value_prop("comment", comment_attr_val.into())); } } @@ -184,8 +183,6 @@ where } } - - let message_descriptor = Expr::Object(ObjectLit { span: message_dscrptr_span, props: message_descriptor_props, diff --git a/tests/__swc_snapshots__/tests/jsx.rs/jsx_preserve_reserved_attrs.js b/tests/__swc_snapshots__/tests/jsx.rs/jsx_preserve_reserved_attrs.js index ec04671..4cffe76 100644 --- a/tests/__swc_snapshots__/tests/jsx.rs/jsx_preserve_reserved_attrs.js +++ b/tests/__swc_snapshots__/tests/jsx.rs/jsx_preserve_reserved_attrs.js @@ -3,6 +3,5 @@ const exp2 =
{p.translation}
} render={(v)=>v}/>; diff --git a/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_plural_preserve_reserved_attrs.js b/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_plural_preserve_reserved_attrs.js index 13ce5c2..7546026 100644 --- a/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_plural_preserve_reserved_attrs.js +++ b/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_plural_preserve_reserved_attrs.js @@ -6,6 +6,5 @@ import { Trans as Trans_ } from "@lingui/react"; }, comment: "Translators Comment", message: "{count, plural, one {...} other {...}}", - context: "Message Context", - comment: "Translators Comment" + context: "Message Context" }} render={(v)=>v}/>; diff --git a/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_select_with_reserved_attrs.js b/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_select_with_reserved_attrs.js index 78dfe75..dab5412 100644 --- a/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_select_with_reserved_attrs.js +++ b/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_select_with_reserved_attrs.js @@ -9,6 +9,5 @@ import { Trans as Trans_ } from "@lingui/react"; }, comment: "Translators Comment", message: "{count, select, male {He} female {She} other {<0>Other}}", - context: "Message Context", - comment: "Translators Comment" + context: "Message Context" }} render={(v)=>v}/>; From 08f9cc40821d1a18af481454312b2c5f47a8c686 Mon Sep 17 00:00:00 2001 From: iatsenko <1586852+timofei-iatsenko@users.noreply.github.com> Date: Tue, 14 Apr 2026 15:27:16 +0200 Subject: [PATCH 3/6] fix --- src/js_macro_folder.rs | 14 ++++++-------- src/lib.rs | 8 +++----- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/js_macro_folder.rs b/src/js_macro_folder.rs index c09354b..4d9e654 100644 --- a/src/js_macro_folder.rs +++ b/src/js_macro_folder.rs @@ -104,10 +104,8 @@ where if let Expr::Object(obj) = *expr { let id_prop = get_object_prop(&obj.props, "id"); - let context_prop = get_object_prop(&obj.props, "context"); - let context_val = context_prop.and_then(|prop| get_expr_as_string(&prop.value)); - - let comment_prop = get_object_prop(&obj.props, "comment"); + let context_val = get_object_prop(&obj.props, "context") + .and_then(|prop| get_expr_as_string(&prop.value)); let message_prop = get_object_prop(&obj.props, "message"); @@ -152,10 +150,10 @@ where } if self.ctx.options.descriptor_fields.should_keep_comment() { - if let Some(prop) = comment_prop { - if let Some(value) = get_expr_as_string(&prop.value) { - new_props.push(create_key_value_prop("comment", value.into())); - } + if let Some(value) = get_object_prop(&obj.props, "comment") + .and_then(|prop| get_expr_as_string(&prop.value)) + { + new_props.push(create_key_value_prop("comment", value.into())); } } diff --git a/src/lib.rs b/src/lib.rs index 4c130bf..aca374b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -153,12 +153,10 @@ where } if self.ctx.options.descriptor_fields.should_keep_comment() { - let comment_attr = - get_jsx_attr(&el.opening, "comment").and_then(|attr| attr.value.as_ref()); - - if let Some(comment_attr) = comment_attr { - let comment_attr_val = get_jsx_attr_value_as_string(comment_attr).unwrap(); + let comment_attr_val = get_jsx_attr(&el.opening, "comment") + .and_then(|attr| get_jsx_attr_value_as_string(attr.value.as_ref()?)); + if let Some(comment_attr_val) = comment_attr_val { message_descriptor_props .push(create_key_value_prop("comment", comment_attr_val.into())); } From 535d47fb1d5a3a93acb6c9b41515186715439a85 Mon Sep 17 00:00:00 2001 From: iatsenko <1586852+timofei-iatsenko@users.noreply.github.com> Date: Tue, 14 Apr 2026 15:33:53 +0200 Subject: [PATCH 4/6] fixes --- src/js_macro_folder.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/js_macro_folder.rs b/src/js_macro_folder.rs index 4d9e654..1607a0e 100644 --- a/src/js_macro_folder.rs +++ b/src/js_macro_folder.rs @@ -111,10 +111,8 @@ where let mut new_props: Vec = vec![]; - if let Some(prop) = id_prop { - if let Some(value) = get_expr_as_string(&prop.value) { - new_props.push(create_key_value_prop("id", value.into())); - } + if let Some(value) = id_prop.and_then(|prop| get_expr_as_string(&prop.value)) { + new_props.push(create_key_value_prop("id", value.into())); } if let Some(prop) = message_prop { @@ -144,8 +142,8 @@ where } if self.ctx.options.descriptor_fields.should_keep_context() { - if let Some(context_str) = &context_val { - new_props.push(create_key_value_prop("context", context_str.clone().into())); + if let Some(context) = context_val { + new_props.push(create_key_value_prop("context", context.into())); } } From b696b46c16e4f872138a5d8b2b186c05bd5694fa Mon Sep 17 00:00:00 2001 From: iatsenko <1586852+timofei-iatsenko@users.noreply.github.com> Date: Fri, 17 Apr 2026 11:23:49 +0200 Subject: [PATCH 5/6] fix --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index aca374b..9a5973f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -167,9 +167,9 @@ where } if self.ctx.options.descriptor_fields.should_keep_context() { - if let Some(context_attr) = context_attr { - let context_attr_val = get_jsx_attr_value_as_string(context_attr).unwrap(); - + if let Some(context_attr_val) = + context_attr.and_then(get_jsx_attr_value_as_string) + { message_descriptor_props.push(create_key_value_prop( "context", Box::new(Expr::Lit(Lit::Str(Str { From f63efc644e7aea385bf828a18df4f4c854816f91 Mon Sep 17 00:00:00 2001 From: iatsenko <1586852+timofei-iatsenko@users.noreply.github.com> Date: Fri, 17 Apr 2026 13:12:10 +0200 Subject: [PATCH 6/6] fix --- src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9a5973f..9dcfaf4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -167,9 +167,7 @@ where } if self.ctx.options.descriptor_fields.should_keep_context() { - if let Some(context_attr_val) = - context_attr.and_then(get_jsx_attr_value_as_string) - { + if let Some(context_attr_val) = context_attr.and_then(get_jsx_attr_value_as_string) { message_descriptor_props.push(create_key_value_prop( "context", Box::new(Expr::Lit(Lit::Str(Str {