Skip to content

Commit a2013d2

Browse files
committed
fix(l10n): harden Swift localization resolution
1 parent 41be60e commit a2013d2

5 files changed

Lines changed: 2073 additions & 241 deletions

File tree

grapha-swift/src/lib.rs

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,10 @@ fn source_contains_l10n_markers(source: &[u8]) -> bool {
345345
|| bytes_contains(source, b"LocalizedStringKey")
346346
|| bytes_contains(source, b"Text(\"")
347347
|| bytes_contains(source, b"Text(.")
348+
|| bytes_contains(source, b"Text(i18n:")
349+
|| bytes_contains(source, b"String(i18n:")
350+
|| bytes_contains(source, b"i18n:")
351+
|| bytes_contains(source, b".translation")
348352
|| bytes_contains(source, b"Localizable")
349353
}
350354

@@ -398,7 +402,7 @@ pub fn extract_swift(
398402
// Parse once, share tree across all enrichment passes.
399403
// Check which enrichment passes are needed before parsing
400404
let has_swiftui = source_contains_swiftui_markers(source);
401-
let has_l10n = source_contains_l10n_markers(source);
405+
let has_l10n = has_swiftui || source_contains_l10n_markers(source);
402406
let has_assets = source_contains_asset_markers(source);
403407
let needs_doc = result.nodes.iter().any(|n| n.doc_comment.is_none());
404408
let needs_parse = needs_doc || has_swiftui || has_l10n || has_assets;
@@ -506,7 +510,7 @@ fn enrich_fallback_result(
506510
result: &mut ExtractionResult,
507511
) -> anyhow::Result<()> {
508512
let has_swiftui = source_contains_swiftui_markers(source);
509-
let has_l10n = source_contains_l10n_markers(source);
513+
let has_l10n = has_swiftui || source_contains_l10n_markers(source);
510514
let has_assets = source_contains_asset_markers(source);
511515
let needs_tree = has_swiftui || has_l10n || has_assets;
512516

@@ -756,9 +760,10 @@ mod discovery_cache_tests {
756760
#[cfg(test)]
757761
mod marker_tests {
758762
use super::{
759-
source_contains_asset_markers, source_contains_l10n_markers,
760-
source_contains_swiftui_markers,
763+
extract_swift_via_fallback_for_tests, source_contains_asset_markers,
764+
source_contains_l10n_markers, source_contains_swiftui_markers,
761765
};
766+
use std::path::Path;
762767

763768
#[test]
764769
fn swiftui_markers_ignore_plain_imports() {
@@ -804,9 +809,48 @@ mod marker_tests {
804809
assert!(source_contains_l10n_markers(
805810
br#"Text(.accountForgetPassword)"#
806811
));
812+
assert!(source_contains_l10n_markers(br#"Text(i18n: .commonShare)"#));
813+
assert!(source_contains_l10n_markers(
814+
br#"String(i18n: .commonShare)"#
815+
));
807816
assert!(source_contains_l10n_markers(
808817
br#"NSLocalizedString("hello", comment: "")"#
809818
));
810819
assert!(source_contains_asset_markers(br#"Image("logo")"#));
811820
}
821+
822+
#[test]
823+
fn fallback_runs_l10n_enrichment_for_swiftui_custom_views_without_explicit_markers() {
824+
let source = br#"
825+
import SwiftUI
826+
827+
struct TitleRow: View {
828+
let title: String
829+
830+
var body: some View {
831+
Text(title)
832+
}
833+
}
834+
835+
struct ContentView: View {
836+
let title: String
837+
838+
var body: some View {
839+
TitleRow(title: title)
840+
}
841+
}
842+
"#;
843+
844+
let result =
845+
extract_swift_via_fallback_for_tests(source, Path::new("ContentView.swift")).unwrap();
846+
847+
assert!(
848+
result.nodes.iter().any(|node| {
849+
node.metadata
850+
.get("l10n.ref_kind")
851+
.is_some_and(|value| value == "possible_string")
852+
}),
853+
"SwiftUI files should still receive l10n enrichment even without explicit L10n markers"
854+
);
855+
}
812856
}

0 commit comments

Comments
 (0)