Skip to main content

Rest/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	/// Current file being processed
18	pub current_file:Option<String>,
19	/// Regex patterns for different localize calls
20	localize_pattern:Regex,
21	localize2_pattern:Regex,
22}
23
24impl NLSExtractor {
25	pub fn new() -> Self {
26		Self {
27			entries:HashMap::new(),
28			current_file:None,
29			// Match nls.localize('key', 'value') or localize('key', 'value')
30			localize_pattern:Regex::new(r#"(?:nls\.)?localize\s*\(\s*['"]([^'"]+)['"]\s*,\s*['"]([^'"]*)['"]\s*\)"#)
31				.unwrap(),
32			// Match nls.localize2('key', 'v1', 'v2')
33			localize2_pattern:Regex::new(
34				r#"(?:nls\.)?localize2\s*\(\s*['"]([^'"]+)['"]\s*,\s*['"]([^'"]*)['"]\s*,\s*['"]([^'"]*)['"]\s*\)"#,
35			)
36			.unwrap(),
37		}
38	}
39
40	pub fn with_file(mut self, file:impl Into<String>) -> Self {
41		self.current_file = Some(file.into());
42		self
43	}
44
45	/// Extract keys from source content
46	pub fn extract(&mut self, source:&str) {
47		// Extract from localize() calls
48		for cap in self.localize_pattern.captures_iter(source) {
49			if let (Some(key), Some(value)) = (cap.get(1), cap.get(2)) {
50				self.entries
51					.entry(key.as_str().to_string())
52					.or_insert(value.as_str().to_string());
53			}
54		}
55
56		// Extract from localize2() calls (use first value)
57		for cap in self.localize2_pattern.captures_iter(source) {
58			if let (Some(key), Some(value)) = (cap.get(1), cap.get(2)) {
59				self.entries
60					.entry(key.as_str().to_string())
61					.or_insert(value.as_str().to_string());
62			}
63		}
64	}
65}
66
67impl Default for NLSExtractor {
68	fn default() -> Self { Self::new() }
69}
70
71/// Extract NLS keys from source code using regex
72pub fn extract_nls_keys(source:&str) -> HashMap<String, String> {
73	let mut extractor = NLSExtractor::new();
74	extractor.extract(source);
75	extractor.entries
76}
77
78#[cfg(test)]
79mod tests {
80	use super::*;
81
82	#[test]
83	fn test_extract_simple_localize() {
84		let source = r#"
85            const str = nls.localize('hello', 'Hello World');
86        "#;
87		let keys = extract_nls_keys(source);
88		assert_eq!(keys.get("hello"), Some(&"Hello World".to_string()));
89	}
90
91	#[test]
92	fn test_extract_multiple_keys() {
93		let source = r#"
94            const a = localize('key1', 'Value 1');
95            const b = nls.localize('key2', 'Value 2');
96        "#;
97		let keys = extract_nls_keys(source);
98		assert_eq!(keys.get("key1"), Some(&"Value 1".to_string()));
99		assert_eq!(keys.get("key2"), Some(&"Value 2".to_string()));
100	}
101
102	#[test]
103	fn test_extract_localize2() {
104		let source = r#"
105            const str = nls.localize2('key', 'Value 1', 'Value 2');
106        "#;
107		let keys = extract_nls_keys(source);
108		assert_eq!(keys.get("key"), Some(&"Value 1".to_string()));
109	}
110}