Skip to main content

Library/Fn/NLS/
Extract.rs

1//! NLS key extraction from TypeScript source files
2//!
3//! Extracts localization keys from various patterns:
4//! - nls.localize('key', 'default')
5//! - nls.localize2('key', 'default1', 'default2')
6//! - nls.localizeWithFlattenedArgs(...)
7//! - localize('key', 'default')
8
9use std::collections::HashMap;
10
11use regex::Regex;
12
13/// Extracts NLS keys from TypeScript source
14pub struct NLSExtractor {
15	/// Extracted localization entries
16	pub entries:HashMap<String, String>,
17
18	/// Current file being processed
19	pub current_file:Option<String>,
20
21	/// Regex patterns for different localize calls
22	localize_pattern:Regex,
23
24	localize2_pattern:Regex,
25}
26
27impl NLSExtractor {
28	pub fn new() -> Self {
29		Self {
30			entries:HashMap::new(),
31
32			current_file:None,
33
34			// Match nls.localize('key', 'value') or localize('key', 'value')
35			localize_pattern:Regex::new(r#"(?:nls\.)?localize\s*\(\s*['"]([^'"]+)['"]\s*,\s*['"]([^'"]*)['"]\s*\)"#)
36				.unwrap(),
37
38			// Match nls.localize2('key', 'v1', 'v2')
39			localize2_pattern:Regex::new(
40				r#"(?:nls\.)?localize2\s*\(\s*['"]([^'"]+)['"]\s*,\s*['"]([^'"]*)['"]\s*,\s*['"]([^'"]*)['"]\s*\)"#,
41			)
42			.unwrap(),
43		}
44	}
45
46	pub fn with_file(mut self, file:impl Into<String>) -> Self {
47		self.current_file = Some(file.into());
48
49		self
50	}
51
52	/// Extract keys from source content
53	pub fn extract(&mut self, source:&str) {
54		// Extract from localize() calls
55		for cap in self.localize_pattern.captures_iter(source) {
56			if let (Some(key), Some(value)) = (cap.get(1), cap.get(2)) {
57				self.entries
58					.entry(key.as_str().to_string())
59					.or_insert(value.as_str().to_string());
60			}
61		}
62
63		// Extract from localize2() calls (use first value)
64		for cap in self.localize2_pattern.captures_iter(source) {
65			if let (Some(key), Some(value)) = (cap.get(1), cap.get(2)) {
66				self.entries
67					.entry(key.as_str().to_string())
68					.or_insert(value.as_str().to_string());
69			}
70		}
71	}
72}
73
74impl Default for NLSExtractor {
75	fn default() -> Self { Self::new() }
76}
77
78/// Extract NLS keys from source code using regex
79pub fn extract_nls_keys(source:&str) -> HashMap<String, String> {
80	let mut extractor = NLSExtractor::new();
81
82	extractor.extract(source);
83
84	extractor.entries
85}
86
87#[cfg(test)]
88mod tests {
89
90	use super::*;
91
92	#[test]
93	fn test_extract_simple_localize() {
94		let source = r#"
95            const str = nls.localize('hello', 'Hello World');
96
97        "#;
98
99		let keys = extract_nls_keys(source);
100
101		assert_eq!(keys.get("hello"), Some(&"Hello World".to_string()));
102	}
103
104	#[test]
105	fn test_extract_multiple_keys() {
106		let source = r#"
107            const a = localize('key1', 'Value 1');
108
109            const b = nls.localize('key2', 'Value 2');
110
111        "#;
112
113		let keys = extract_nls_keys(source);
114
115		assert_eq!(keys.get("key1"), Some(&"Value 1".to_string()));
116
117		assert_eq!(keys.get("key2"), Some(&"Value 2".to_string()));
118	}
119
120	#[test]
121	fn test_extract_localize2() {
122		let source = r#"
123            const str = nls.localize2('key', 'Value 1', 'Value 2');
124
125        "#;
126
127		let keys = extract_nls_keys(source);
128
129		assert_eq!(keys.get("key"), Some(&"Value 1".to_string()));
130	}
131}