@@ -40,7 +40,7 @@ struct LocalizableStrings : WhiteListedExtensionsResourceType {
4040 let dictionary : [ String : ( params: [ StringParam ] , commentValue: String ) ]
4141 switch url. pathExtension {
4242 case " strings " ? :
43- dictionary = try parseStrings ( nsDictionary , source: locale. withFilename ( " \( filename) .strings " ) )
43+ dictionary = try parseStrings ( String ( contentsOfURL : url ) , source: locale. withFilename ( " \( filename) .strings " ) )
4444 case " stringsdict " ? :
4545 dictionary = try parseStringsdict ( nsDictionary, source: locale. withFilename ( " \( filename) .stringsdict " ) )
4646 default :
@@ -53,37 +53,63 @@ struct LocalizableStrings : WhiteListedExtensionsResourceType {
5353 }
5454}
5555
56- private func parseStrings( nsDictionary : NSDictionary , source: String ) throws -> [ String : ( params: [ StringParam ] , commentValue: String ) ] {
56+ private func parseStrings( stringsFile : String , source: String ) throws -> [ String : ( params: [ StringParam ] , commentValue: String ) ] {
5757 var dictionary : [ String : ( params: [ StringParam ] , commentValue: String ) ] = [ : ]
5858
59- for ( key, obj) in nsDictionary {
60- if let
61- key = key as? String ,
62- val = obj as? String
63- {
59+ for entry in StringsEntry . parse ( stringsFile) {
6460 var params : [ StringParam ] = [ ]
6561
66- for part in FormatPart . formatParts ( formatString: val) {
62+ for part in FormatPart . formatParts ( formatString: entry . val) {
6763 switch part {
6864 case . Reference:
69- throw ResourceParsingError . ParsingFailed ( " Non-specifier reference in \( source) : \( key) = \( val) " )
65+ throw ResourceParsingError . ParsingFailed ( " Non-specifier reference in \( source) : \( entry . key) = \( entry . val) " )
7066
7167 case . Spec( let formatSpecifier) :
7268 params. append ( StringParam ( name: nil , spec: formatSpecifier) )
7369 }
7470 }
7571
76-
77- dictionary [ key] = ( params, val)
78- }
79- else {
80- throw ResourceParsingError . ParsingFailed ( " Non-string value in \( source) : \( key) = \( obj) " )
81- }
72+ dictionary [ entry. key] = ( params, entry. val)
8273 }
8374
8475 return dictionary
8576}
8677
78+ private struct StringsEntry {
79+ let comment : String ?
80+ let key : String
81+ let val : String
82+
83+ static let regex : NSRegularExpression = {
84+ let capturedTrimmedComment = " /[*] \\ s* (.*?) \\ s* [*]/ "
85+ let whitespaceOrComment = " (?: \\ s | /[*] .*? [*]/) "
86+ let slash = " \\ \\ "
87+ let quotedString = " \" .*? (?<! \( slash) ) \" "
88+ let unquotedString = " [^ \\ s \( slash) \" =]+ "
89+ let string = " (?: \( quotedString) | \( unquotedString) ) "
90+ let pattern = " (?: \( capturedTrimmedComment) )? \\ s* ( \( string) ) \( whitespaceOrComment) * = \( whitespaceOrComment) * ( \( string) ) \( whitespaceOrComment) * ; "
91+ return try ! NSRegularExpression ( pattern: pattern, options: [ . AllowCommentsAndWhitespace, . DotMatchesLineSeparators] )
92+ } ( )
93+
94+ init ( source: String , match: NSTextCheckingResult ) {
95+ guard match. numberOfRanges == 4 else { fatalError ( " must be used with StringsEntry.regex " ) }
96+ func extract( range: NSRange , unescape: Bool ) -> String ? {
97+ guard range. location != NSNotFound else { return nil }
98+ let raw = ( source as NSString ) . substringWithRange ( range)
99+ if !unescape { return raw }
100+ return try ! NSPropertyListSerialization . propertyListWithData ( raw. dataUsingEncoding ( NSUTF8StringEncoding) !, options: [ ] , format: nil ) as! String
101+ }
102+ comment = extract ( match. rangeAtIndex ( 1 ) , unescape: false )
103+ key = extract ( match. rangeAtIndex ( 2 ) , unescape: true ) !
104+ val = extract ( match. rangeAtIndex ( 3 ) , unescape: true ) !
105+ }
106+
107+ static func parse( stringsFileContents: String ) -> [ StringsEntry ] {
108+ return regex. matchesInString ( stringsFileContents, options: [ ] , range: NSRange ( 0 ..< stringsFileContents. utf16. count) )
109+ . map { StringsEntry ( source: stringsFileContents, match: $0) }
110+ }
111+ }
112+
87113private func parseStringsdict( nsDictionary: NSDictionary , source: String ) throws -> [ String : ( params: [ StringParam ] , commentValue: String ) ] {
88114
89115 var dictionary : [ String : ( params: [ StringParam ] , commentValue: String ) ] = [ : ]
0 commit comments