Skip to content
This repository was archived by the owner on Jun 29, 2022. It is now read-only.

Commit 4adc59d

Browse files
author
Hèctor Marquès
committed
Initial commit
0 parents  commit 4adc59d

36 files changed

+889
-0
lines changed

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
## macOS
3+
4+
.DS_Store
5+
6+
## SPM
7+
8+
/.build
9+
/Packages
10+
/*.xcodeproj
11+
/.swiftpm

.swiftformat

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# https://github.com/nicklockwood/SwiftFormat#rules
2+
# https://github.com/nicklockwood/SwiftFormat/blob/master/CHANGELOG.md
3+
# https://github.com/nicklockwood/SwiftFormat/blob/master/Rules.md
4+
5+
# Swift version
6+
--swiftversion 5.1
7+
8+
# file options
9+
--exclude Sources/unstringify/Internal/template.swift
10+
11+
# rules
12+
--disable redundantReturn

.swiftlint.yml

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# https://github.com/realm/SwiftLint
2+
# https://github.com/realm/SwiftLint/blob/master/CHANGELOG.md
3+
# https://raw.githubusercontent.com/realm/SwiftLint/master/Rules.md
4+
5+
included: # paths to include during linting. `--path` is ignored if present.
6+
- Sources
7+
8+
disabled_rules: # rule identifiers to exclude from running
9+
- identifier_name
10+
- trailing_comma
11+
12+
opt_in_rules: # all opt-in rules up to version 0.35.0
13+
- anyobject_protocol
14+
- array_init
15+
- attributes
16+
- closure_body_length
17+
- closure_end_indentation
18+
- closure_spacing
19+
- collection_alignment
20+
- conditional_returns_on_newline
21+
- contains_over_filter_count
22+
- contains_over_filter_is_empty
23+
- contains_over_first_not_nil
24+
- contains_over_range_nil_comparison
25+
- convenience_type
26+
- discouraged_object_literal
27+
- discouraged_optional_boolean
28+
- discouraged_optional_collection
29+
- empty_collection_literal
30+
- empty_count
31+
- empty_string
32+
- empty_xctest_method
33+
# - explicit_acl
34+
- explicit_enum_raw_value
35+
- explicit_init
36+
- explicit_self
37+
# - explicit_top_level_acl
38+
# - explicit_type_interface
39+
# - extension_access_modifier
40+
- fallthrough
41+
- fatal_error_message
42+
- file_header
43+
# - file_name
44+
- file_types_order
45+
- first_where
46+
- force_unwrapping
47+
- function_default_parameter_at_end
48+
- identical_operands
49+
# - implicit_return
50+
- implicitly_unwrapped_optional
51+
- joined_default_parameter
52+
- last_where
53+
- legacy_multiple
54+
- legacy_random
55+
- let_var_whitespace
56+
- literal_expression_end_indentation
57+
- lower_acl_than_parent
58+
# - missing_docs
59+
- modifier_order
60+
- multiline_arguments
61+
# - multiline_arguments_brackets
62+
- multiline_function_chains
63+
- multiline_literal_brackets
64+
- multiline_parameters
65+
- multiline_parameters_brackets
66+
- nimble_operator
67+
- no_extension_access_modifier
68+
- no_grouping_extension
69+
# - nslocalizedstring_key
70+
- nslocalizedstring_require_bundle
71+
- number_separator
72+
- object_literal
73+
- operator_usage_whitespace
74+
- overridden_super_call
75+
- override_in_extension
76+
- pattern_matching_keywords
77+
# - prefixed_toplevel_constant
78+
- private_action
79+
- private_outlet
80+
- prohibited_interface_builder
81+
- prohibited_super_call
82+
- quick_discouraged_call
83+
- quick_discouraged_focused_test
84+
- quick_discouraged_pending_test
85+
- reduce_into
86+
- redundant_nil_coalescing
87+
- redundant_type_annotation
88+
- required_deinit
89+
- required_enum_case
90+
- single_test_class
91+
- sorted_first_last
92+
- sorted_imports
93+
- static_operator
94+
- strict_fileprivate
95+
- strong_iboutlet
96+
# - switch_case_on_newline
97+
- toggle_bool
98+
- trailing_closure
99+
- type_contents_order
100+
- unavailable_function
101+
- unneeded_parentheses_in_closure_argument
102+
- unowned_variable_capture
103+
- untyped_error_in_catch
104+
- unused_declaration
105+
- unused_import
106+
- vertical_parameter_alignment_on_call
107+
- vertical_whitespace
108+
- vertical_whitespace_between_cases
109+
- vertical_whitespace_closing_braces
110+
- vertical_whitespace_opening_braces
111+
- xct_specific_matcher
112+
- yoda_condition
113+
114+
# Customized rules:
115+
116+
line_length: 180
117+
118+
cyclomatic_complexity:
119+
ignores_case_statements: true

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2019 Metropolis:Lab
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
22+

Package.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// swift-tools-version:5.1
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "Unstringify",
7+
targets: [
8+
.target(
9+
name: "unstringify",
10+
dependencies: ["Unstringified"]),
11+
.target(
12+
name: "Unstringified",
13+
dependencies: []),
14+
.testTarget(
15+
name: "UnstringifyTests",
16+
dependencies: ["unstringify"]),
17+
.testTarget(
18+
name: "UnstringifiedTests",
19+
dependencies: ["Unstringified"]),
20+
]
21+
)

README.md

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# Unstringify
2+
3+
## What?
4+
5+
- `unstringify` (CLI): Code generator for strong-typing localizable strings.
6+
- `Unstringified` (module): Strong-typed localizable strings static source code.
7+
8+
## Why?
9+
10+
It makes your localized strings code:
11+
12+
- compile time checked,
13+
- strong typed,
14+
- autocompletable by Xcode.
15+
16+
## How?
17+
18+
### Installation
19+
20+
There are several methods to install Unstringify:
21+
22+
- Via [CocoaPods](https://cocoapods.org)
23+
- Via [Swift Package Manager](https://swift.org/package-manager)
24+
- Others:
25+
- Download the ZIP for the [latest release](https://github.com/metrolab/Unstringify/releases/latest)
26+
- Via [Mint](https://github.com/yonaskolb/Mint) (system-wide installation)
27+
- Compile from [source](https://github.com/metrolab/Unstringify.git) (only recommended if you need features from master or want to test a PR)
28+
29+
#### CocoaPods
30+
31+
Add `unstringify` specs to your `Podfile`:
32+
33+
```ruby
34+
pod 'Unstringify'
35+
```
36+
37+
Add `Unstringified` as dependency in the podspec of the module that contains the strings files:
38+
39+
```ruby
40+
s.dependency 'Unstringified'
41+
```
42+
**Note:** *If your app is not modularized, simply add `pod 'Unstringified'` to your `Podfile` too.*
43+
44+
Add a Build Phase that generates the code for the `Unstringified` enumerations:
45+
46+
```bash
47+
"$PODS_ROOT/Unstringify/unstringify" "$SRCROOT/path/to/module/en.lproj/Localizable.strings" "$SRCROOT/path/to/module/Unstringified.generated.string"
48+
```
49+
50+
#### Swift Package Manager
51+
52+
Declare `Unstringify` dependency in your `Package.swift` file:
53+
54+
```swift
55+
dependencies: [
56+
.package(url: "https://github.com/metrolab/Unstringify", from: "0.1.0"),
57+
]
58+
```
59+
60+
Execute the CLI passing as arguments the *input strings file* and the *path to generated output file*:
61+
62+
```sh
63+
swift run unstringify path/to/module/en.lproj/Localizable.string path/to/module/Unstringified.generated.string
64+
```
65+
66+
In order to use the generated file, you will need to *link* `Unstringified` to the module that contains the generated file and the original strings files.
67+
68+
### Example
69+
70+
CLI usage:
71+
72+
```
73+
$ ./unstringify
74+
Usage: ./unstringify inputPath outputPath
75+
```
76+
77+
Input (e.g. `en.lproj/Localizable.strings`):
78+
79+
```
80+
"form_title" = "Contact";
81+
"form_name_field" = "Name:";
82+
"form_name_field_max_length" = "Maximum length is %d characters.";
83+
"form_name_field_description" = "Enter your <b>full name</b>";
84+
```
85+
86+
Output (e.g. `Unstringified.generated.swift`):
87+
88+
```
89+
// Generated by Unstringify.
90+
// DO NOT EDIT!
91+
92+
import Unstringified
93+
94+
private final class _Unstringified {}
95+
96+
extension Unstringified {
97+
public var localizableStringsBundle: Bundle {
98+
return Bundle(for: _Unstringified.self)
99+
}
100+
}
101+
102+
public enum Text: String, Unstringified {
103+
public typealias StringType = String
104+
case form_title, form_name_field
105+
}
106+
107+
public enum Format: Unstringified {
108+
public typealias StringType = String
109+
case form_name_field_max_length(Int)
110+
}
111+
112+
public enum RichText: String, Unstringified {
113+
public typealias StringType = NSAttributedString
114+
case form_name_field_description
115+
}
116+
117+
public enum RichFormat: Unstringified {
118+
public typealias StringType = NSAttributedString
119+
case 👻()
120+
}
121+
```
122+
123+
## License
124+
125+
Unstringify is released under the MIT license. See `LICENSE` for details.
126+
127+
# Alternatives
128+
129+
- <https://github.com/mac-cain13/R.swift>
130+
- <https://github.com/bannzai/ResourceKit>
131+
- <https://github.com/kaandedeoglu/Shark>
132+
- <https://github.com/SwiftGen/SwiftGen>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import Foundation
2+
3+
extension NSAttributedString {
4+
func uppercased() -> NSAttributedString {
5+
let result = NSMutableAttributedString(attributedString: self)
6+
7+
result.enumerateAttributes(in: NSRange(location: 0, length: length), options: []) { _, range, _ in
8+
result.replaceCharacters(in: range, with: (string as NSString).substring(with: range).uppercased())
9+
}
10+
11+
return result
12+
}
13+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import Foundation
2+
3+
extension String {
4+
func countOccurrences(of string: String) -> Int {
5+
guard !isEmpty else {
6+
return 0
7+
}
8+
return components(separatedBy: string).count - 1
9+
}
10+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#if os(OSX)
2+
import AppKit
3+
#else
4+
import UIKit
5+
#endif
6+
7+
extension String {
8+
func toAttributed() -> NSAttributedString {
9+
let data = Data(utf8)
10+
let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [
11+
.documentType: NSAttributedString.DocumentType.html,
12+
.characterEncoding: String.Encoding.utf8.rawValue,
13+
]
14+
guard let attributed = try? NSMutableAttributedString(data: data,
15+
options: options,
16+
documentAttributes: nil)
17+
else { return NSMutableAttributedString(string: strippingMarkup()) }
18+
return attributed
19+
}
20+
21+
private func strippingMarkup() -> String {
22+
return replacingOccurrences(of: "<b>", with: "")
23+
.replacingOccurrences(of: "</b>", with: "")
24+
.replacingOccurrences(of: "<i>", with: "")
25+
.replacingOccurrences(of: "</i>", with: "")
26+
}
27+
}

0 commit comments

Comments
 (0)