Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
3f64e9682c |
2
Jenkinsfile
vendored
2
Jenkinsfile
vendored
@ -1,6 +1,6 @@
|
||||
library "openiumpipeline"
|
||||
|
||||
env.DEVELOPER_DIR="/Applications/Xcode-15.4.0.app/Contents/Developer"
|
||||
env.DEVELOPER_DIR="/Applications/Xcode-15.0.1.app/Contents/Developer"
|
||||
//env.SIMULATOR_DEVICE_TYPES="iPad--7th-generation-"
|
||||
env.IS_PACKAGE_SWIFT=1
|
||||
env.TARGETS_MACOS=1
|
||||
|
@ -1,5 +1,59 @@
|
||||
{
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "collectionconcurrencykit",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/JohnSundell/CollectionConcurrencyKit.git",
|
||||
"state" : {
|
||||
"revision" : "b4f23e24b5a1bff301efc5e70871083ca029ff95",
|
||||
"version" : "0.2.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "cryptoswift",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/krzyzanowskim/CryptoSwift.git",
|
||||
"state" : {
|
||||
"revision" : "db51c407d3be4a051484a141bf0bff36c43d3b1e",
|
||||
"version" : "1.8.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "pathkit",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/kylef/PathKit.git",
|
||||
"state" : {
|
||||
"revision" : "3bfd2737b700b9a36565a8c94f4ad2b050a5e574",
|
||||
"version" : "1.0.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "sourcekitten",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/jpsim/SourceKitten.git",
|
||||
"state" : {
|
||||
"revision" : "b6dc09ee51dfb0c66e042d2328c017483a1a5d56",
|
||||
"version" : "0.34.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "spectre",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/kylef/Spectre.git",
|
||||
"state" : {
|
||||
"revision" : "26cc5e9ae0947092c7139ef7ba612e34646086c7",
|
||||
"version" : "0.10.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "stencil",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/stencilproject/Stencil.git",
|
||||
"state" : {
|
||||
"revision" : "4f222ac85d673f35df29962fc4c36ccfdaf9da5b",
|
||||
"version" : "0.15.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-argument-parser",
|
||||
"kind" : "remoteSourceControl",
|
||||
@ -10,12 +64,39 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swiftlintplugin",
|
||||
"identity" : "swift-syntax",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/lukepistrol/SwiftLintPlugin",
|
||||
"location" : "https://github.com/apple/swift-syntax.git",
|
||||
"state" : {
|
||||
"revision" : "5a65f4074975f811da666dfe31a19850950b1ea4",
|
||||
"version" : "0.56.2"
|
||||
"revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036",
|
||||
"version" : "509.0.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swiftlint",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/realm/SwiftLint.git",
|
||||
"state" : {
|
||||
"revision" : "f17a4f9dfb6a6afb0408426354e4180daaf49cee",
|
||||
"version" : "0.54.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swiftytexttable",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/scottrhoyt/SwiftyTextTable.git",
|
||||
"state" : {
|
||||
"revision" : "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3",
|
||||
"version" : "0.9.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swxmlhash",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/drmohundro/SWXMLHash.git",
|
||||
"state" : {
|
||||
"revision" : "a853604c9e9a83ad9954c7e3d2a565273982471f",
|
||||
"version" : "7.0.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -10,7 +10,8 @@ let package = Package(
|
||||
// Dependencies declare other packages that this package depends on.
|
||||
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0"),
|
||||
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.1"),
|
||||
.package(url: "https://github.com/lukepistrol/SwiftLintPlugin", exact: "0.56.2"),
|
||||
.package(url: "https://github.com/realm/SwiftLint.git", .upToNextMajor(from: "0.54.0")),
|
||||
.package(url: "https://github.com/stencilproject/Stencil.git", .upToNextMajor(from: "0.15.1")),
|
||||
],
|
||||
targets: [
|
||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||
@ -20,11 +21,10 @@ let package = Package(
|
||||
dependencies: [
|
||||
"ToolCore",
|
||||
.product(name: "ArgumentParser", package: "swift-argument-parser"),
|
||||
"Yams"
|
||||
"Yams",
|
||||
"Stencil",
|
||||
],
|
||||
plugins: [
|
||||
.plugin(name: "SwiftLint", package: "SwiftLintPlugin")
|
||||
]
|
||||
plugins: [.plugin(name: "SwiftLintPlugin", package: "SwiftLint")]
|
||||
),
|
||||
|
||||
// Helper targets
|
||||
|
86
README.md
86
README.md
@ -81,7 +81,7 @@ swift run -c release ResgenSwift strings twine $FORCE_FLAG "./Twine/strings.txt"
|
||||
2. Input translations file (must be Twine formatted)
|
||||
3. `--langs`: langs to generate (string with space between each lang)
|
||||
4. `--default-lang`: default lang that will be in `Base.lproj`. It must be in `langs` as well
|
||||
5. `--extension-output-path`: path where to generate generated extension
|
||||
4. `--extension-output-path`: path where to generate generated extension
|
||||
|
||||
### Stringium (recommended)
|
||||
|
||||
@ -93,7 +93,6 @@ swift run -c release ResgenSwift strings stringium $FORCE_FLAG "./Strings/string
|
||||
--extension-output-path "./Strings/Generated" \
|
||||
--extension-name "AppString" \
|
||||
--extension-suffix "GreatApp" \
|
||||
--xcStrings true
|
||||
--static-members true
|
||||
```
|
||||
|
||||
@ -106,7 +105,6 @@ swift run -c release ResgenSwift strings stringium $FORCE_FLAG "./Strings/string
|
||||
4. `--extension-output-path`: path where to generate generated extension
|
||||
5. `--extension-name` *(optional)* : name of class to add the extension
|
||||
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppString+GreatApp.swift`)
|
||||
6. `--xcStrings`*(optional)* : generate string catalog
|
||||
7. `--static-members` *(optional)*: generate static properties or not
|
||||
|
||||
|
||||
@ -133,7 +131,7 @@ swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \
|
||||
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppTags+GreatApp.swift`)
|
||||
7. `--static-members` *(optional)*: generate static properties or not
|
||||
|
||||
> ⚠️ If extension name is not set or is `Tags`, it will generate the following typealias `typealias Tags = String`.
|
||||
> ⚠️ If extension name is not set or is `Tags`, it will generate the following typaloas `typealias Tags = String`.
|
||||
|
||||
|
||||
## Analytics
|
||||
@ -141,7 +139,7 @@ swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \
|
||||
Analytics will generate all you need to analyze UX with Matomo or Firebase Analytics. Input files are formatted in YAML. This command will generate a manager for each target and an AnalyticsManager. This is this one you will need to use. And it will generate a method for all tags you have declared in the YAML file. Next, you will need to use the `configure()` method of AnalyticsManager and if you want to use matomo to set up the `siteId` and the `url` of the site.
|
||||
|
||||
```sh
|
||||
swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/analytics.yml" \
|
||||
swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \
|
||||
--target "matomo firebase" \
|
||||
--extension-output-path "./Analytics/Generated" \
|
||||
--extension-name "AppAnalytics" \
|
||||
@ -159,7 +157,7 @@ swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/analytics.yml" \
|
||||
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppAnalytics+GreatApp.swift`)
|
||||
7. `--static-members` *(optional)*: generate static properties or not
|
||||
|
||||
> ⚠️ If extension name is not set or is `Analytics`, it will generate the following typealias `typealias Analytics = String`.
|
||||
> ⚠️ If extension name is not set or is `Analytics`, it will generate the following typaloas `typealias Analytics = String`.
|
||||
|
||||
### YAML
|
||||
|
||||
@ -192,77 +190,13 @@ You can use parameters in generate methods.
|
||||
|
||||
1. `name`: name of the parameter
|
||||
2. `type`: type of the parameter (Int, String, Bool, Double)
|
||||
3. `value`: value of the parameter
|
||||
4. `defaultValue`: defaultValue of the parameter
|
||||
3. `replaceIn` *(optional)*
|
||||
|
||||
**Value**
|
||||
|
||||
If you want to send another parameter with a static value. For example, you want to send to which screen the event is triggered.
|
||||
You can add the parameter 'screenName' for example and its 'value' is 'Home'. With this, you do not need to specify the value in the function call.
|
||||
|
||||
**DefaultValue**
|
||||
|
||||
If you want ta add a parameter in the call of the function but you want to make it optionnal with a default value you need to use this property.
|
||||
|
||||
Example:
|
||||
```
|
||||
events:
|
||||
id: id_of_tag
|
||||
name: _TITLE_
|
||||
tags: ios,droid
|
||||
parameters:
|
||||
- name: title
|
||||
type: String
|
||||
defaultValue: someTitle
|
||||
```
|
||||
|
||||
The generated method will be:
|
||||
```
|
||||
logIdOfTag(title: String = "someTitle")
|
||||
```
|
||||
|
||||
**Replace in**
|
||||
|
||||
This is section is equivalent of `%s | %d | %f | %@`. You can put the content of the parameter in *name*, *path*, *action*, *category*.
|
||||
You need to put `_` + `NAME OF THE PARAMETER` + `_` in the target and which target you want in the value of `replaceIn`. (name need to be in uppercase).
|
||||
You can't use `value`and `replaceIn`in thge same time.
|
||||
You need to put `_` + `NAME OF THE PARAMETER` + `_` in the target and which target you want in the value of `replaceIn`. (name need to be in uppercase)
|
||||
|
||||
Example:
|
||||
```
|
||||
events:
|
||||
id: id_of_tag
|
||||
name: _TITLE_
|
||||
tags: ios,droid
|
||||
parameters:
|
||||
- name: title
|
||||
type: String
|
||||
replaceIn: name
|
||||
```
|
||||
|
||||
In this sample, we want to add the parameter `title` in the field `name`. So, we need to place `_TITLE_` in the field `name`.
|
||||
|
||||
The generated method will be:
|
||||
```
|
||||
logIdOfTag(title: String)
|
||||
```
|
||||
|
||||
You can also want to replace a parameter in an other parameter. You can do this with the `replaceIn` property. The condition is that the parameter which will use the `replaceIn`need to have the `value`property
|
||||
|
||||
Example:
|
||||
```
|
||||
events:
|
||||
id: id_of_tag
|
||||
name: title
|
||||
tags: ios,droid
|
||||
parameters:
|
||||
- name: something
|
||||
type: String
|
||||
value: test _TEXT_
|
||||
- name: text
|
||||
type: String
|
||||
replaceIn: something
|
||||
```
|
||||
|
||||
## Images
|
||||
|
||||
@ -289,7 +223,6 @@ swift run -c release ResgenSwift images $FORCE_FLAG "./Images/images.txt" \
|
||||
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppImage+GreatApp.swift`)
|
||||
7. `--static-members` *(optional)*: generate static properties or not
|
||||
|
||||
> ⚠️ Svg images will be copied in the assets and rendered as "Original", however if those images are not rendered correctly you can force the png generation by adding the key word "png" like this: id arrow_back 15 ? png
|
||||
|
||||
## All at once
|
||||
|
||||
@ -351,15 +284,6 @@ tags:
|
||||
extensionName: String?
|
||||
extensionSuffix: String?
|
||||
staticMembers: Bool?
|
||||
|
||||
analytics:
|
||||
-
|
||||
inputFile: String
|
||||
target: String
|
||||
extensionOutputPath: String
|
||||
extensionName: String?
|
||||
extensionSuffix: String?
|
||||
staticMembers: Bool?
|
||||
```
|
||||
|
||||
### Multiple configurations
|
||||
|
@ -4,18 +4,25 @@ import SwiftUI
|
||||
|
||||
extension ColorYolo {
|
||||
|
||||
/// Color red is #FF0000 (light) or #FF0000 (dark)"
|
||||
|
||||
/// Color red is #FF0000 #FF0000 or #FF0000 #FF0000"
|
||||
var red: Color {
|
||||
Color("red")
|
||||
}
|
||||
|
||||
/// Color green_alpha_50 is #A000FF00 (light) or #A000FF00 (dark)"
|
||||
|
||||
|
||||
/// Color green_alpha_50 is #A000FF00 #A000FF00 or #A000FF00 #A000FF00"
|
||||
var green_alpha_50: Color {
|
||||
Color("green_alpha_50")
|
||||
}
|
||||
|
||||
/// Color blue_light_dark is #0000FF (light) or #0000AA (dark)"
|
||||
|
||||
|
||||
/// Color blue_light_dark is #0000FF #0000FF or #0000AA #0000AA"
|
||||
var blue_light_dark: Color {
|
||||
Color("blue_light_dark")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -4,18 +4,25 @@ import UIKit
|
||||
|
||||
extension UIColorYolo {
|
||||
|
||||
/// Color red is #FF0000 (light) or #FF0000 (dark)"
|
||||
|
||||
/// Color red is #FF0000 #FF0000 or #FF0000 #FF0000"
|
||||
@objc var red: UIColor {
|
||||
UIColor(named: "red")!
|
||||
}
|
||||
|
||||
/// Color green_alpha_50 is #A000FF00 (light) or #A000FF00 (dark)"
|
||||
|
||||
|
||||
/// Color green_alpha_50 is #A000FF00 #A000FF00 or #A000FF00 #A000FF00"
|
||||
@objc var green_alpha_50: UIColor {
|
||||
UIColor(named: "green_alpha_50")!
|
||||
}
|
||||
|
||||
/// Color blue_light_dark is #0000FF (light) or #0000AA (dark)"
|
||||
|
||||
|
||||
/// Color blue_light_dark is #0000FF #0000FF or #0000AA #0000AA"
|
||||
@objc var blue_light_dark: UIColor {
|
||||
UIColor(named: "blue_light_dark")!
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
// Generated by ResgenSwift.Color 1.2
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
extension UIhkjhkColorYolo {
|
||||
|
||||
|
||||
/// Color red is #FF0000 #FF0000 or #FF0000 #FF0000"
|
||||
@objc var red: UIColor {
|
||||
UIColor(named: "red")!
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// Color green_alpha_50 is #A000FF00 #A000FF00 or #A000FF00 #A000FF00"
|
||||
@objc var green_alpha_50: UIColor {
|
||||
UIColor(named: "green_alpha_50")!
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// Color blue_light_dark is #0000FF #0000FF or #0000AA #0000AA"
|
||||
@objc var blue_light_dark: UIColor {
|
||||
UIColor(named: "blue_light_dark")!
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -6,20 +6,13 @@ import FirebaseAnalytics
|
||||
// MARK: - Protocol
|
||||
|
||||
protocol AnalyticsManagerProtocol {
|
||||
func logScreen(
|
||||
name: String,
|
||||
path: String,
|
||||
params: [String: Any]?
|
||||
)
|
||||
|
||||
func logScreen(name: String, path: String)
|
||||
func logEvent(
|
||||
name: String,
|
||||
action: String,
|
||||
category: String,
|
||||
params: [String: Any]?
|
||||
)
|
||||
|
||||
func setEnable(_ enable: Bool)
|
||||
}
|
||||
|
||||
// MARK: - Matomo
|
||||
@ -54,11 +47,8 @@ class MatomoAnalyticsManager: AnalyticsManagerProtocol {
|
||||
|
||||
// MARK: - Methods
|
||||
|
||||
func logScreen(
|
||||
name: String,
|
||||
path: String,
|
||||
params: [String: Any]?
|
||||
) {
|
||||
func logScreen(name: String, path: String) {
|
||||
guard !tracker.isOptedOut else { return }
|
||||
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
|
||||
|
||||
let urlString = URL(string: "\(trackerUrl)" + "/" + "\(path)" + "iOS")
|
||||
@ -74,6 +64,8 @@ class MatomoAnalyticsManager: AnalyticsManagerProtocol {
|
||||
category: String,
|
||||
params: [String: Any]?
|
||||
) {
|
||||
guard !tracker.isOptedOut else { return }
|
||||
|
||||
tracker.track(
|
||||
eventWithCategory: category,
|
||||
action: action,
|
||||
@ -82,40 +74,16 @@ class MatomoAnalyticsManager: AnalyticsManagerProtocol {
|
||||
url: nil
|
||||
)
|
||||
}
|
||||
|
||||
func setEnable(_ enable: Bool) {
|
||||
tracker.isOptedOut = !enable
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Firebase
|
||||
|
||||
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
||||
func logScreen(
|
||||
name: String,
|
||||
path: String,
|
||||
params: [String: Any]?
|
||||
) {
|
||||
func logScreen(name: String, path: String) {
|
||||
var parameters = [
|
||||
AnalyticsParameterScreenName: name as NSObject
|
||||
]
|
||||
|
||||
if path.isEmpty == false {
|
||||
parameters["path"] = path + "/iOS" as NSObject
|
||||
}
|
||||
|
||||
if let supplementaryParameters = params {
|
||||
for (newKey, newValue) in supplementaryParameters {
|
||||
if parameters.contains(where: { (key: String, value: NSObject) in
|
||||
key == newKey
|
||||
}) {
|
||||
continue
|
||||
}
|
||||
|
||||
parameters[newKey] = newValue as? NSObject
|
||||
}
|
||||
}
|
||||
|
||||
Analytics.logEvent(
|
||||
AnalyticsEventScreenView,
|
||||
parameters: parameters
|
||||
@ -129,17 +97,10 @@ class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
||||
params: [String: Any]?
|
||||
) {
|
||||
var parameters: [String:NSObject] = [
|
||||
AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject
|
||||
"action": action as NSObject,
|
||||
"category": category as NSObject,
|
||||
]
|
||||
|
||||
if category.isEmpty == false {
|
||||
parameters["AnalyticsParameterItemCategory"] = category as NSObject
|
||||
}
|
||||
|
||||
if action.isEmpty == false {
|
||||
parameters["action"] = action as NSObject
|
||||
}
|
||||
|
||||
if let supplementaryParameters = params {
|
||||
for (newKey, newValue) in supplementaryParameters {
|
||||
if parameters.contains(where: { (key: String, value: NSObject) in
|
||||
@ -153,13 +114,10 @@ class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
||||
}
|
||||
|
||||
Analytics.logEvent(
|
||||
AnalyticsEventSelectContent,
|
||||
name.replacingOccurrences(of: [" "], with: "_"),
|
||||
parameters: parameters
|
||||
)
|
||||
}
|
||||
func setEnable(_ enable: Bool) {
|
||||
Analytics.setAnalyticsCollectionEnabled(enable)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Manager
|
||||
@ -169,57 +127,31 @@ class AnalyticsManager {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
var managers: [TargetType: AnalyticsManagerProtocol] = []
|
||||
var managers: [AnalyticsManagerProtocol] = []
|
||||
|
||||
private var isEnabled: Bool {
|
||||
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
private var isEnabled: Bool = true
|
||||
|
||||
// MARK: - Methods
|
||||
|
||||
private func setAnalytics(enable: Bool) {
|
||||
managers.forEach { (key, value) in
|
||||
if analytics.contains(where: { type in
|
||||
type == key
|
||||
}) {
|
||||
value.setEnable(enable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func enableAnalytics(_ analytics: [TargetType] = TargetType.allCases) {
|
||||
setAnalytics(enable: true)
|
||||
}
|
||||
|
||||
func disableAnalytics(_ analytics: [TargetType] = TargetType.allCases) {
|
||||
setAnalytics(enable: false)
|
||||
func setAnalyticsEnabled(_ enable: Bool) {
|
||||
isEnabled = enable
|
||||
}
|
||||
|
||||
func configure(siteId: String, url: String) {
|
||||
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
||||
managers.append(
|
||||
MatomoAnalyticsManager(
|
||||
siteId: siteId,
|
||||
url: url
|
||||
)
|
||||
managers[TrackerType.firebase] = FirebaseAnalyticsManager()
|
||||
)
|
||||
managers.append(FirebaseAnalyticsManager())
|
||||
}
|
||||
|
||||
private func logScreen(
|
||||
name: String,
|
||||
path: String,
|
||||
params: [String: Any]?
|
||||
) {
|
||||
private func logScreen(name: String, path: String) {
|
||||
guard isEnabled else { return }
|
||||
|
||||
managers.values.forEach { manager in
|
||||
manager.logScreen(
|
||||
name: name,
|
||||
path: path,
|
||||
params: params
|
||||
)
|
||||
managers.forEach { manager in
|
||||
manager.logScreen(name: name, path: path)
|
||||
}
|
||||
}
|
||||
|
||||
@ -231,7 +163,7 @@ class AnalyticsManager {
|
||||
) {
|
||||
guard isEnabled else { return }
|
||||
|
||||
managers.values.forEach { manager in
|
||||
managers.forEach { manager in
|
||||
manager.logEvent(
|
||||
name: name,
|
||||
action: action,
|
||||
@ -243,39 +175,31 @@ class AnalyticsManager {
|
||||
|
||||
// MARK: - section_one
|
||||
|
||||
static func logScreenS1DefOne(title: String) {
|
||||
AnalyticsManager.shared.logScreen(
|
||||
func logScreenS1DefOne(title: String) {
|
||||
logScreen(
|
||||
name: "s1 def one \(title)",
|
||||
path: "s1_def_one/\(title)",
|
||||
params: nil
|
||||
path: "s1_def_one/\(title)"
|
||||
)
|
||||
}
|
||||
|
||||
static func logEventS1DefTwo(
|
||||
title: String,
|
||||
count: String,
|
||||
test2: String = "test"
|
||||
) {
|
||||
AnalyticsManager.shared.logEvent(
|
||||
func logEventS1DefTwo(title: String, count: String) {
|
||||
logEvent(
|
||||
name: "s1 def two",
|
||||
action: "test",
|
||||
category: "test",
|
||||
params: [
|
||||
"title": title,
|
||||
"count": count,
|
||||
"test": "test",
|
||||
"test2": test2
|
||||
"count": count
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - section_two
|
||||
|
||||
static func logScreenS2DefOne() {
|
||||
AnalyticsManager.shared.logScreen(
|
||||
func logScreenS2DefOne() {
|
||||
logScreen(
|
||||
name: "s2 def one",
|
||||
path: "s2_def_one/",
|
||||
params: nil
|
||||
path: "s2_def_one/"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -22,12 +22,6 @@ categories:
|
||||
type: String
|
||||
- name: count
|
||||
type: String
|
||||
- name: test
|
||||
type: String
|
||||
value: test
|
||||
- name: test2
|
||||
type: String
|
||||
defaultValue: test
|
||||
|
||||
- id: section_two
|
||||
screens:
|
||||
|
@ -12,14 +12,14 @@ FORCE_FLAG="$1"
|
||||
#
|
||||
#echo "\n-------------------------\n"
|
||||
#
|
||||
## Color
|
||||
#swift run -c release ResgenSwift colors $FORCE_FLAG "./Colors/sampleColors1.txt" \
|
||||
# --style all \
|
||||
# --xcassets-path "./Colors/colors.xcassets" \
|
||||
# --extension-output-path "./Colors/Generated/" \
|
||||
# --extension-name "ColorYolo" \
|
||||
# --extension-name-ui-kit "UIhkjhkColorYolo" \
|
||||
# --extension-suffix "GenAllScript"
|
||||
# Color
|
||||
swift run -c release ResgenSwift colors $FORCE_FLAG "./Colors/sampleColors1.txt" \
|
||||
--style all \
|
||||
--xcassets-path "./Colors/colors.xcassets" \
|
||||
--extension-output-path "./Colors/Generated/" \
|
||||
--extension-name "ColorYolo" \
|
||||
--extension-name-ui-kit "UIColorYolo" \
|
||||
--extension-suffix "GenAllScript"
|
||||
#
|
||||
#echo "\n-------------------------\n"
|
||||
#
|
||||
@ -52,13 +52,12 @@ FORCE_FLAG="$1"
|
||||
|
||||
#echo "\n-------------------------\n"
|
||||
|
||||
# Analytics
|
||||
swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/sampleTags.yml" \
|
||||
--target "firebase matomo" \
|
||||
--extension-output-path "./Tags/Generated" \
|
||||
--extension-name "Analytics" \
|
||||
--extension-suffix "GenAllScript" \
|
||||
--static-members true
|
||||
## Analytics
|
||||
#swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/sampleTags.yml" \
|
||||
# --target "matomo firebase" \
|
||||
# --extension-output-path "./Tags/Generated" \
|
||||
# --extension-name "Analytics" \
|
||||
# --extension-suffix "GenAllScript"
|
||||
|
||||
#echo "\n-------------------------\n"
|
||||
#
|
||||
|
@ -59,18 +59,14 @@ class AnalyticsGenerator {
|
||||
\(Self.getImport())
|
||||
|
||||
\(Self.getAnalyticsProtocol())
|
||||
|
||||
\(Self.getTrackerTypeEnum())
|
||||
|
||||
// MARK: - Manager
|
||||
|
||||
class AnalyticsManager {
|
||||
|
||||
static var shared = AnalyticsManager()
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
|
||||
var managers: [AnalyticsManagerProtocol] = []
|
||||
|
||||
\(Self.getEnabledContent())
|
||||
|
||||
@ -80,49 +76,14 @@ class AnalyticsGenerator {
|
||||
"""
|
||||
}
|
||||
|
||||
private static func getTrackerTypeEnum() -> String {
|
||||
var result: [String] = []
|
||||
TrackerType.allCases.forEach { type in
|
||||
result.append(" case \(type)")
|
||||
}
|
||||
|
||||
return """
|
||||
// MARK: - Traker Type
|
||||
|
||||
enum TrackerType: CaseIterable {
|
||||
\(result.joined(separator: "\n"))
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
private static func getEnabledContent() -> String {
|
||||
"""
|
||||
private var isEnabled: Bool {
|
||||
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
private var isEnabled: Bool = true
|
||||
|
||||
// MARK: - Methods
|
||||
|
||||
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
||||
managers.forEach { (key, value) in
|
||||
if analytics.contains(where: { type in
|
||||
type == key
|
||||
}) {
|
||||
value.setEnable(enable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
||||
setAnalytics(enable: true, analytics)
|
||||
}
|
||||
|
||||
func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
||||
setAnalytics(enable: false, analytics)
|
||||
func setAnalyticsEnabled(_ enable: Bool) {
|
||||
isEnabled = enable
|
||||
}
|
||||
"""
|
||||
}
|
||||
@ -142,19 +103,11 @@ class AnalyticsGenerator {
|
||||
|
||||
private static func getPrivateLogFunction() -> String {
|
||||
"""
|
||||
private func logScreen(
|
||||
name: String,
|
||||
path: String,
|
||||
params: [String: Any]?
|
||||
) {
|
||||
private func logScreen(name: String, path: String) {
|
||||
guard isEnabled else { return }
|
||||
|
||||
managers.values.forEach { manager in
|
||||
manager.logScreen(
|
||||
name: name,
|
||||
path: path,
|
||||
params: params
|
||||
)
|
||||
managers.forEach { manager in
|
||||
manager.logScreen(name: name, path: path)
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,7 +119,7 @@ class AnalyticsGenerator {
|
||||
) {
|
||||
guard isEnabled else { return }
|
||||
|
||||
managers.values.forEach { manager in
|
||||
managers.forEach { manager in
|
||||
manager.logEvent(
|
||||
name: name,
|
||||
action: action,
|
||||
@ -191,14 +144,16 @@ class AnalyticsGenerator {
|
||||
|
||||
if targets.contains(TrackerType.matomo) {
|
||||
content.append("""
|
||||
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
||||
managers.append(
|
||||
MatomoAnalyticsManager(
|
||||
siteId: siteId,
|
||||
url: url
|
||||
)
|
||||
)
|
||||
""")
|
||||
}
|
||||
if targets.contains(TrackerType.firebase) {
|
||||
content.append(" managers[TrackerType.firebase] = FirebaseAnalyticsManager()")
|
||||
content.append(" managers.append(FirebaseAnalyticsManager())")
|
||||
}
|
||||
|
||||
return [
|
||||
@ -214,20 +169,13 @@ class AnalyticsGenerator {
|
||||
// MARK: - Protocol
|
||||
|
||||
protocol AnalyticsManagerProtocol {
|
||||
func logScreen(
|
||||
name: String,
|
||||
path: String,
|
||||
params: [String: Any]?
|
||||
)
|
||||
|
||||
func logScreen(name: String, path: String)
|
||||
func logEvent(
|
||||
name: String,
|
||||
action: String,
|
||||
category: String,
|
||||
params: [String: Any]?
|
||||
)
|
||||
|
||||
func setEnable(_ enable: Bool)
|
||||
}
|
||||
|
||||
"""
|
||||
|
@ -14,7 +14,6 @@ enum FirebaseGenerator {
|
||||
FirebaseGenerator.header,
|
||||
FirebaseGenerator.logScreen,
|
||||
FirebaseGenerator.logEvent,
|
||||
FirebaseGenerator.enable,
|
||||
FirebaseGenerator.footer
|
||||
]
|
||||
.joined(separator: "\n")
|
||||
@ -32,31 +31,11 @@ enum FirebaseGenerator {
|
||||
|
||||
private static var logScreen: String {
|
||||
"""
|
||||
func logScreen(
|
||||
name: String,
|
||||
path: String,
|
||||
params: [String: Any]?
|
||||
) {
|
||||
func logScreen(name: String, path: String) {
|
||||
var parameters = [
|
||||
AnalyticsParameterScreenName: name as NSObject
|
||||
]
|
||||
|
||||
if path.isEmpty == false {
|
||||
parameters["path"] = path + "/iOS" as NSObject
|
||||
}
|
||||
|
||||
if let supplementaryParameters = params {
|
||||
for (newKey, newValue) in supplementaryParameters {
|
||||
if parameters.contains(where: { (key: String, value: NSObject) in
|
||||
key == newKey
|
||||
}) {
|
||||
continue
|
||||
}
|
||||
|
||||
parameters[newKey] = newValue as? NSObject
|
||||
}
|
||||
}
|
||||
|
||||
Analytics.logEvent(
|
||||
AnalyticsEventScreenView,
|
||||
parameters: parameters
|
||||
@ -75,17 +54,10 @@ enum FirebaseGenerator {
|
||||
params: [String: Any]?
|
||||
) {
|
||||
var parameters: [String:NSObject] = [
|
||||
AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject
|
||||
"action": action as NSObject,
|
||||
"category": category as NSObject,
|
||||
]
|
||||
|
||||
if category.isEmpty == false {
|
||||
parameters["AnalyticsParameterItemCategory"] = category as NSObject
|
||||
}
|
||||
|
||||
if action.isEmpty == false {
|
||||
parameters["action"] = action as NSObject
|
||||
}
|
||||
|
||||
if let supplementaryParameters = params {
|
||||
for (newKey, newValue) in supplementaryParameters {
|
||||
if parameters.contains(where: { (key: String, value: NSObject) in
|
||||
@ -99,21 +71,13 @@ enum FirebaseGenerator {
|
||||
}
|
||||
|
||||
Analytics.logEvent(
|
||||
AnalyticsEventSelectContent,
|
||||
name.replacingOccurrences(of: [" "], with: "_"),
|
||||
parameters: parameters
|
||||
)
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
private static var enable: String {
|
||||
"""
|
||||
func setEnable(_ enable: Bool) {
|
||||
Analytics.setAnalyticsCollectionEnabled(enable)
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
private static var footer: String {
|
||||
"""
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ enum MatomoGenerator {
|
||||
MatomoGenerator.setup,
|
||||
MatomoGenerator.logScreen,
|
||||
MatomoGenerator.logEvent,
|
||||
MatomoGenerator.enable,
|
||||
MatomoGenerator.footer
|
||||
]
|
||||
.joined(separator: "\n")
|
||||
@ -67,11 +66,8 @@ enum MatomoGenerator {
|
||||
|
||||
private static var logScreen: String {
|
||||
"""
|
||||
func logScreen(
|
||||
name: String,
|
||||
path: String,
|
||||
params: [String: Any]?
|
||||
) {
|
||||
func logScreen(name: String, path: String) {
|
||||
guard !tracker.isOptedOut else { return }
|
||||
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
|
||||
|
||||
let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS")
|
||||
@ -92,6 +88,8 @@ enum MatomoGenerator {
|
||||
category: String,
|
||||
params: [String: Any]?
|
||||
) {
|
||||
guard !tracker.isOptedOut else { return }
|
||||
|
||||
tracker.track(
|
||||
eventWithCategory: category,
|
||||
action: action,
|
||||
@ -100,15 +98,6 @@ enum MatomoGenerator {
|
||||
url: nil
|
||||
)
|
||||
}
|
||||
|
||||
"""
|
||||
}
|
||||
|
||||
private static var enable: String {
|
||||
"""
|
||||
func setEnable(_ enable: Bool) {
|
||||
tracker.isOptedOut = !enable
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
|
@ -48,23 +48,17 @@ class AnalyticsDefinition {
|
||||
}
|
||||
|
||||
private func getParameters() -> String {
|
||||
var params = parameters
|
||||
var result: String
|
||||
|
||||
let paramsString = parameters.compactMap { parameter -> String? in
|
||||
guard parameter.value.isEmpty else { return nil }
|
||||
|
||||
let defaultValue: String
|
||||
switch parameter.type {
|
||||
case .bool:
|
||||
defaultValue = "\(parameter.defaultValue.lowercased())"
|
||||
case .int, .double:
|
||||
defaultValue = "\(parameter.defaultValue)"
|
||||
case .string:
|
||||
defaultValue = "\"\(parameter.defaultValue)\""
|
||||
if type == .screen {
|
||||
params = params.filter { param in
|
||||
!param.replaceIn.isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
let defaultValueString = parameter.defaultValue.isEmpty ? "" : " = \(defaultValue)"
|
||||
return "\(parameter.name): \(parameter.type.rawValue)\(defaultValueString)"
|
||||
let paramsString = params.map { parameter in
|
||||
"\(parameter.name): \(parameter.type)"
|
||||
}
|
||||
|
||||
if paramsString.count > 2 {
|
||||
@ -90,10 +84,7 @@ class AnalyticsDefinition {
|
||||
case "path": path = path.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||
case "category": category = category.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||
case "action": action = action.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||
default:
|
||||
if let param = parameters.first(where: { $0.name == rep }), param.value.isEmpty == false {
|
||||
param.value = param.value.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||
}
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -108,18 +99,7 @@ class AnalyticsDefinition {
|
||||
}
|
||||
|
||||
supplementaryParams.forEach { param in
|
||||
if param.value.isEmpty {
|
||||
params.append("\"\(param.name)\": \(param.name)")
|
||||
} else {
|
||||
switch param.type {
|
||||
case .bool:
|
||||
params.append("\"\(param.name)\": \(param.value.lowercased())")
|
||||
case .int, .double:
|
||||
params.append("\"\(param.name)\": \(param.value)")
|
||||
case .string:
|
||||
params.append("\"\(param.name)\": \"\(param.value)\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if params.count > 1 {
|
||||
@ -133,15 +113,14 @@ class AnalyticsDefinition {
|
||||
[\(params.joined(separator: ", "))]
|
||||
"""
|
||||
} else {
|
||||
result = "nil"
|
||||
result = "[:]"
|
||||
}
|
||||
|
||||
if type == .screen {
|
||||
return """
|
||||
logScreen(
|
||||
name: "\(name)",
|
||||
path: "\(path)",
|
||||
params: \(result)
|
||||
path: "\(path)"
|
||||
)
|
||||
"""
|
||||
} else {
|
||||
@ -171,7 +150,7 @@ class AnalyticsDefinition {
|
||||
replaceIn()
|
||||
return """
|
||||
static func \(getFuncName())\(getParameters()) {
|
||||
AnalyticsManager.shared.\(getlogFunction())
|
||||
\(getlogFunction())
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
@ -41,7 +41,5 @@ struct AnalyticsDefinitionEventDTO: Codable {
|
||||
struct AnalyticsParameterDTO: Codable {
|
||||
var name: String
|
||||
var type: String
|
||||
var value: String?
|
||||
var defaultValue: String?
|
||||
var replaceIn: String?
|
||||
}
|
||||
|
@ -9,17 +9,13 @@ import Foundation
|
||||
|
||||
class AnalyticsParameter {
|
||||
var name: String
|
||||
var type: ParameterType
|
||||
var value: String
|
||||
var defaultValue: String
|
||||
var type: String
|
||||
var replaceIn: [String] = []
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
init(name: String, type: ParameterType, value: String, defaultValue: String) {
|
||||
init(name: String, type: String) {
|
||||
self.name = name
|
||||
self.type = type
|
||||
self.value = value
|
||||
self.defaultValue = defaultValue
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
//
|
||||
// File.swift
|
||||
//
|
||||
//
|
||||
// Created by Loris Perret on 17/07/2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum ParameterType: String {
|
||||
case string = "String"
|
||||
case int = "Int"
|
||||
case double = "Double"
|
||||
case bool = "Bool"
|
||||
}
|
@ -30,58 +30,25 @@ class AnalyticsFileParser {
|
||||
}
|
||||
|
||||
private static func getParameters(from parameters: [AnalyticsParameterDTO]) -> [AnalyticsParameter] {
|
||||
func verify(value: String?, for type: ParameterType) {
|
||||
guard let value, value.isEmpty == false else { return }
|
||||
|
||||
switch type {
|
||||
case .int:
|
||||
if Int(value) == nil {
|
||||
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
||||
print(error.description)
|
||||
Analytics.exit(withError: error)
|
||||
}
|
||||
case .bool:
|
||||
if Bool(value.lowercased()) == nil {
|
||||
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
||||
print(error.description)
|
||||
Analytics.exit(withError: error)
|
||||
}
|
||||
case .double:
|
||||
if Double(value) == nil {
|
||||
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
||||
print(error.description)
|
||||
Analytics.exit(withError: error)
|
||||
}
|
||||
case .string:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return parameters.map { dtoParameter in
|
||||
parameters.map { dtoParameter in
|
||||
// Type
|
||||
|
||||
let type = dtoParameter.type.uppercasedFirst()
|
||||
|
||||
guard let typeEnum = ParameterType(rawValue: type) else {
|
||||
guard
|
||||
type == "String" ||
|
||||
type == "Int" ||
|
||||
type == "Double" ||
|
||||
type == "Bool"
|
||||
else {
|
||||
let error = AnalyticsError.invalidParameter("type of \(dtoParameter.name)")
|
||||
print(error.description)
|
||||
Analytics.exit(withError: error)
|
||||
}
|
||||
|
||||
if dtoParameter.value != nil, dtoParameter.replaceIn != nil {
|
||||
let error = AnalyticsError.invalidParameter("you can't set 'value' and 'replaceIn' for \(dtoParameter.name)")
|
||||
print(error.description)
|
||||
Analytics.exit(withError: error)
|
||||
}
|
||||
|
||||
verify(value: dtoParameter.value, for: typeEnum)
|
||||
verify(value: dtoParameter.defaultValue, for: typeEnum)
|
||||
|
||||
let parameter = AnalyticsParameter(
|
||||
name: dtoParameter.name,
|
||||
type: typeEnum,
|
||||
value: dtoParameter.value ?? "",
|
||||
defaultValue: dtoParameter.defaultValue ?? ""
|
||||
type: type
|
||||
)
|
||||
|
||||
if let replaceIn = dtoParameter.replaceIn {
|
||||
@ -136,8 +103,6 @@ class AnalyticsFileParser {
|
||||
Analytics.exit(withError: error)
|
||||
}
|
||||
|
||||
definition.path = path
|
||||
} else if let path = screen.path {
|
||||
definition.path = path
|
||||
}
|
||||
|
||||
@ -174,14 +139,6 @@ class AnalyticsFileParser {
|
||||
}
|
||||
|
||||
definition.action = action
|
||||
} else {
|
||||
if let category = event.category {
|
||||
definition.category = category
|
||||
}
|
||||
|
||||
if let action = event.action {
|
||||
definition.action = action
|
||||
}
|
||||
}
|
||||
|
||||
return definition
|
||||
|
@ -41,12 +41,28 @@ struct ColorExtensionGenerator {
|
||||
staticVar: Bool,
|
||||
extensionName: String,
|
||||
isSwiftUI: Bool) -> String {
|
||||
[
|
||||
Self.getHeader(extensionClassname: extensionName, isSwiftUI: isSwiftUI),
|
||||
Self.getProperties(for: colors, withStaticVar: staticVar, isSwiftUI: isSwiftUI),
|
||||
Self.getFooter()
|
||||
// [
|
||||
// Self.getHeader(extensionClassname: extensionName, isSwiftUI: isSwiftUI),
|
||||
// Self.getProperties(for: colors, withStaticVar: staticVar, isSwiftUI: isSwiftUI),
|
||||
// Self.getFooter()
|
||||
// ]
|
||||
// .joined(separator: "\n")
|
||||
do {
|
||||
let context: [String: Any] = [
|
||||
"colors": colors,
|
||||
"isStatic": staticVar,
|
||||
"isSwiftUI": isSwiftUI,
|
||||
"toolName": Colors.toolName,
|
||||
"resgenVersion": ResgenSwiftVersion,
|
||||
"extensionClassname": extensionName
|
||||
]
|
||||
.joined(separator: "\n")
|
||||
|
||||
return try ResgenSwift.environment.renderTemplate(name: "Colors/main_template", context: context)
|
||||
} catch {
|
||||
// let error = ColorsToolError.writeExtension(extensionFilePath, error.localizedDescription)
|
||||
// print(error.description)
|
||||
Colors.exit(withError: error)
|
||||
}
|
||||
}
|
||||
|
||||
private static func getHeader(extensionClassname: String, isSwiftUI: Bool) -> String {
|
||||
|
@ -9,7 +9,7 @@ import Foundation
|
||||
|
||||
enum GenerateError: Error {
|
||||
case fileNotExists(String)
|
||||
case invalidConfigurationFile(String, String)
|
||||
case invalidConfigurationFile(String)
|
||||
case commandError([String], String)
|
||||
case writeFile(String, String)
|
||||
|
||||
@ -18,8 +18,8 @@ enum GenerateError: Error {
|
||||
case .fileNotExists(let filename):
|
||||
return "error: [\(Generate.toolName)] File \(filename) does not exists"
|
||||
|
||||
case .invalidConfigurationFile(let filename, let underneathErrorDescription):
|
||||
return "error: [\(Generate.toolName)] File \(filename) is not a valid configuration file. Underneath error: \(underneathErrorDescription)"
|
||||
case .invalidConfigurationFile(let filename):
|
||||
return "error: [\(Generate.toolName)] File \(filename) is not a valid configuration file"
|
||||
|
||||
case .commandError(let command, let terminationStatus):
|
||||
let readableCommand = command
|
||||
|
@ -269,7 +269,6 @@ struct StringsConfiguration: Codable, CustomDebugStringConvertible {
|
||||
let extensionName: String?
|
||||
let extensionSuffix: String?
|
||||
private let staticMembers: Bool?
|
||||
private let xcStrings: Bool?
|
||||
|
||||
var staticMembersOptions: Bool {
|
||||
if let staticMembers = staticMembers {
|
||||
@ -278,13 +277,6 @@ struct StringsConfiguration: Codable, CustomDebugStringConvertible {
|
||||
return false
|
||||
}
|
||||
|
||||
var xcStringsOptions: Bool {
|
||||
if let xcStrings = xcStrings {
|
||||
return xcStrings
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
internal init(inputFile: String,
|
||||
outputPath: String,
|
||||
langs: String,
|
||||
@ -292,8 +284,7 @@ struct StringsConfiguration: Codable, CustomDebugStringConvertible {
|
||||
extensionOutputPath: String,
|
||||
extensionName: String?,
|
||||
extensionSuffix: String?,
|
||||
staticMembers: Bool?,
|
||||
xcStrings: Bool?) {
|
||||
staticMembers: Bool?) {
|
||||
self.inputFile = inputFile
|
||||
self.outputPath = outputPath
|
||||
self.langs = langs
|
||||
@ -302,7 +293,6 @@ struct StringsConfiguration: Codable, CustomDebugStringConvertible {
|
||||
self.extensionName = extensionName
|
||||
self.extensionSuffix = extensionSuffix
|
||||
self.staticMembers = staticMembers
|
||||
self.xcStrings = xcStrings
|
||||
}
|
||||
|
||||
var debugDescription: String {
|
||||
|
@ -16,15 +16,12 @@ class ConfigurationFileParser {
|
||||
Generate.exit(withError: error)
|
||||
}
|
||||
|
||||
do {
|
||||
return try YAMLDecoder().decode(ConfigurationFile.self, from: data)
|
||||
} catch {
|
||||
let error = GenerateError.invalidConfigurationFile(
|
||||
configurationFile,
|
||||
error.localizedDescription.description
|
||||
)
|
||||
guard let configuration = try? YAMLDecoder().decode(ConfigurationFile.self, from: data) else {
|
||||
let error = GenerateError.invalidConfigurationFile(configurationFile)
|
||||
print(error.description)
|
||||
Generate.exit(withError: error)
|
||||
}
|
||||
|
||||
return configuration
|
||||
}
|
||||
}
|
||||
|
@ -26,9 +26,7 @@ extension StringsConfiguration: Runnable {
|
||||
"--extension-output-path",
|
||||
extensionOutputPath.prependIfRelativePath(projectDirectory),
|
||||
"--static-members",
|
||||
"\(staticMembersOptions)",
|
||||
"--xc-strings",
|
||||
"\(xcStringsOptions)"
|
||||
"\(staticMembersOptions)"
|
||||
]
|
||||
|
||||
if let extensionName = extensionName {
|
||||
|
@ -8,13 +8,10 @@
|
||||
import Foundation
|
||||
import ToolCore
|
||||
|
||||
enum OutputImageExtension: String {
|
||||
case png
|
||||
case svg
|
||||
}
|
||||
|
||||
class XcassetsGenerator {
|
||||
|
||||
static let outputImageExtension = "png"
|
||||
|
||||
let forceGeneration: Bool
|
||||
|
||||
// MARK: - Init
|
||||
@ -63,20 +60,13 @@ class XcassetsGenerator {
|
||||
generatedAssetsPaths.append(imagesetName)
|
||||
|
||||
// Generate output images path
|
||||
let output1x = "\(imagesetPath)/\(parsedImage.name).\(OutputImageExtension.png.rawValue)"
|
||||
let output2x = "\(imagesetPath)/\(parsedImage.name)@2x.\(OutputImageExtension.png.rawValue)"
|
||||
let output3x = "\(imagesetPath)/\(parsedImage.name)@3x.\(OutputImageExtension.png.rawValue)"
|
||||
let output1x = "\(imagesetPath)/\(parsedImage.name).\(XcassetsGenerator.outputImageExtension)"
|
||||
let output2x = "\(imagesetPath)/\(parsedImage.name)@2x.\(XcassetsGenerator.outputImageExtension)"
|
||||
let output3x = "\(imagesetPath)/\(parsedImage.name)@3x.\(XcassetsGenerator.outputImageExtension)"
|
||||
|
||||
// Check if we need to convert image
|
||||
|
||||
var needToGenerateForSvg = false
|
||||
|
||||
if imageData.ext == "svg" && !parsedImage.imageExtensions.contains(.png) {
|
||||
needToGenerateForSvg = true
|
||||
}
|
||||
|
||||
guard self.shouldGenerate(inputImagePath: imageData.path, xcassetImagePath: output1x, needToGenerateForSvg: needToGenerateForSvg) else {
|
||||
print("\(parsedImage.name) -> Not regenerating")
|
||||
guard self.shouldGenerate(inputImagePath: imageData.path, xcassetImagePath: output1x) else {
|
||||
//print("\(parsedImage.name) -> Not regenerating")
|
||||
return
|
||||
}
|
||||
|
||||
@ -90,22 +80,11 @@ class XcassetsGenerator {
|
||||
print(error.description)
|
||||
Images.exit(withError: error)
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
let documentsDirectory = try fileManager.contentsOfDirectory(atPath: imagesetPath)
|
||||
for filePath in documentsDirectory {
|
||||
try fileManager.removeItem(atPath: "\(imagesetPath)/\(filePath)")
|
||||
}
|
||||
} catch {
|
||||
print("Error deleting previous assets")
|
||||
}
|
||||
}
|
||||
|
||||
// Convert image
|
||||
let convertArguments = parsedImage.convertArguments
|
||||
|
||||
if imageData.ext == "svg" {
|
||||
if parsedImage.imageExtensions.contains(.png) {
|
||||
|
||||
// /usr/local/bin/rsvg-convert path/to/image.png -w 200 -h 300 -o path/to/output.png
|
||||
// /usr/local/bin/rsvg-convert path/to/image.png -w 200 -o path/to/output.png
|
||||
// /usr/local/bin/rsvg-convert path/to/image.png -h 300 -o path/to/output.png
|
||||
@ -124,21 +103,6 @@ class XcassetsGenerator {
|
||||
Shell.shell(command1x)
|
||||
Shell.shell(command2x)
|
||||
Shell.shell(command3x)
|
||||
|
||||
} else {
|
||||
|
||||
let output = "\(imagesetPath)/\(parsedImage.name).\(OutputImageExtension.svg.rawValue)"
|
||||
let tempURL = URL(fileURLWithPath: output)
|
||||
|
||||
do {
|
||||
if FileManager.default.fileExists(atPath: tempURL.path) {
|
||||
try FileManager.default.removeItem(atPath: tempURL.path)
|
||||
}
|
||||
try FileManager.default.copyItem(atPath: imageData.path, toPath: tempURL.path)
|
||||
} catch {
|
||||
print(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// convert path/to/image.png -resize 200x300 path/to/output.png
|
||||
// convert path/to/image.png -resize 200x path/to/output.png
|
||||
@ -155,7 +119,7 @@ class XcassetsGenerator {
|
||||
}
|
||||
|
||||
// Write Content.json
|
||||
guard let imagesetContentJson = parsedImage.generateContentJson(isVector: imageData.ext == "svg") else { return }
|
||||
let imagesetContentJson = parsedImage.contentJson
|
||||
let contentJsonFilePath = "\(imagesetPath)/Contents.json"
|
||||
|
||||
let contentJsonFilePathURL = URL(fileURLWithPath: contentJsonFilePath)
|
||||
@ -197,8 +161,8 @@ class XcassetsGenerator {
|
||||
|
||||
// MARK: - Helpers: bypass generation
|
||||
|
||||
private func shouldGenerate(inputImagePath: String, xcassetImagePath: String, needToGenerateForSvg: Bool) -> Bool {
|
||||
if forceGeneration || needToGenerateForSvg {
|
||||
private func shouldGenerate(inputImagePath: String, xcassetImagePath: String) -> Bool {
|
||||
if forceGeneration {
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -1,76 +0,0 @@
|
||||
//
|
||||
// ImageContent.swift
|
||||
//
|
||||
//
|
||||
// Created by Quentin Bandera on 19/04/2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum TemplateRenderingIntent: String, Codable {
|
||||
case template
|
||||
case original
|
||||
}
|
||||
|
||||
struct AssetContent: Codable, Equatable {
|
||||
let images: [AssetImageDescription]
|
||||
let info: AssetInfo
|
||||
let properties: AssetProperties?
|
||||
|
||||
init(
|
||||
images: [AssetImageDescription],
|
||||
info: AssetInfo,
|
||||
properties: AssetProperties? = nil
|
||||
) {
|
||||
self.images = images
|
||||
self.info = info
|
||||
self.properties = properties
|
||||
}
|
||||
|
||||
static func == (lhs: AssetContent, rhs: AssetContent) -> Bool {
|
||||
guard lhs.images.count == rhs.images.count else { return false }
|
||||
let lhsImages = lhs.images.sorted(by: { $0.filename < $1.filename })
|
||||
let rhsImages = rhs.images.sorted(by: { $0.filename < $1.filename })
|
||||
|
||||
return lhsImages == rhsImages
|
||||
}
|
||||
}
|
||||
|
||||
struct AssetImageDescription: Codable, Equatable {
|
||||
let idiom: String
|
||||
let scale: String?
|
||||
let filename: String
|
||||
|
||||
init(
|
||||
idiom: String,
|
||||
scale: String? = nil,
|
||||
filename: String
|
||||
) {
|
||||
self.idiom = idiom
|
||||
self.scale = scale
|
||||
self.filename = filename
|
||||
}
|
||||
}
|
||||
|
||||
struct AssetInfo: Codable, Equatable {
|
||||
let version: Int
|
||||
let author: String
|
||||
}
|
||||
|
||||
struct AssetProperties: Codable, Equatable {
|
||||
let preservesVectorRepresentation: Bool
|
||||
let templateRenderingIntent: TemplateRenderingIntent?
|
||||
|
||||
init(
|
||||
preservesVectorRepresentation: Bool,
|
||||
templateRenderingIntent: TemplateRenderingIntent? = nil
|
||||
) {
|
||||
self.preservesVectorRepresentation = preservesVectorRepresentation
|
||||
self.templateRenderingIntent = templateRenderingIntent
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case preservesVectorRepresentation = "preserves-vector-representation"
|
||||
case templateRenderingIntent = "template-rendering-intent"
|
||||
}
|
||||
}
|
@ -7,30 +7,11 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
enum ImageExtension: String {
|
||||
case png
|
||||
}
|
||||
|
||||
struct ParsedImage {
|
||||
let name: String
|
||||
let tags: String
|
||||
let width: Int
|
||||
let height: Int
|
||||
let imageExtensions: [ImageExtension]
|
||||
|
||||
init(
|
||||
name: String,
|
||||
tags: String,
|
||||
width: Int,
|
||||
height: Int,
|
||||
imageExtensions: [ImageExtension] = []
|
||||
) {
|
||||
self.name = name
|
||||
self.tags = tags
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.imageExtensions = imageExtensions
|
||||
}
|
||||
|
||||
// MARK: - Convert
|
||||
|
||||
@ -61,68 +42,33 @@ struct ParsedImage {
|
||||
|
||||
// MARK: - Assets
|
||||
|
||||
func generateContentJson(isVector: Bool) -> String? {
|
||||
let encoder = JSONEncoder()
|
||||
encoder.outputFormatting = .prettyPrinted
|
||||
|
||||
let imageContent = generateImageContent(isVector: isVector)
|
||||
|
||||
guard let data = try? encoder.encode(imageContent) else {
|
||||
let error = ImagesError.writeFile("Contents.json", "Error encoding json file")
|
||||
print(error.description)
|
||||
Images.exit(withError: error)
|
||||
var contentJson: String {
|
||||
"""
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x",
|
||||
"filename" : "\(name).\(XcassetsGenerator.outputImageExtension)"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "\(name)@2x.\(XcassetsGenerator.outputImageExtension)"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x",
|
||||
"filename" : "\(name)@3x.\(XcassetsGenerator.outputImageExtension)"
|
||||
}
|
||||
|
||||
return String(data: data, encoding: .utf8)
|
||||
}
|
||||
|
||||
func generateImageContent(isVector: Bool) -> AssetContent {
|
||||
|
||||
if !imageExtensions.contains(.png) && isVector {
|
||||
//Generate svg
|
||||
return AssetContent(
|
||||
images: [
|
||||
AssetImageDescription(
|
||||
idiom: "universal",
|
||||
filename: "\(name).\(OutputImageExtension.svg.rawValue)"
|
||||
)
|
||||
],
|
||||
info: AssetInfo(
|
||||
version: 1,
|
||||
author: "ResgenSwift-Imagium"
|
||||
),
|
||||
properties: AssetProperties(
|
||||
preservesVectorRepresentation: true,
|
||||
templateRenderingIntent: .original
|
||||
)
|
||||
)
|
||||
} else {
|
||||
//Generate png
|
||||
return AssetContent(
|
||||
images: [
|
||||
AssetImageDescription(
|
||||
idiom: "universal",
|
||||
scale: "1x",
|
||||
filename: "\(name).\(OutputImageExtension.png.rawValue)"
|
||||
),
|
||||
AssetImageDescription(
|
||||
idiom: "universal",
|
||||
scale: "2x",
|
||||
filename: "\(name)@2x.\(OutputImageExtension.png.rawValue)"
|
||||
),
|
||||
AssetImageDescription(
|
||||
idiom: "universal",
|
||||
scale: "3x",
|
||||
filename: "\(name)@3x.\(OutputImageExtension.png.rawValue)"
|
||||
)
|
||||
],
|
||||
info: AssetInfo(
|
||||
version: 1,
|
||||
author: "ResgenSwift-Imagium"
|
||||
)
|
||||
)
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "ResgenSwift-Imagium"
|
||||
}
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
// MARK: - Extension property
|
||||
|
||||
|
@ -39,20 +39,10 @@ class ImageFileParser {
|
||||
return Int(splittedLine[3])!
|
||||
}()
|
||||
|
||||
var imageExtensions: [ImageExtension] = []
|
||||
|
||||
splittedLine.forEach { stringExtension in
|
||||
if let imageExtension = ImageExtension(rawValue: String(stringExtension)) {
|
||||
imageExtensions.append(imageExtension)
|
||||
}
|
||||
}
|
||||
|
||||
let image = ParsedImage(name: String(splittedLine[1]), tags: String(splittedLine[0]), width: width, height: height, imageExtensions: imageExtensions)
|
||||
let image = ParsedImage(name: String(splittedLine[1]), tags: String(splittedLine[0]), width: width, height: height)
|
||||
imagesToGenerate.append(image)
|
||||
}
|
||||
|
||||
print(imagesToGenerate)
|
||||
|
||||
return imagesToGenerate.filter {
|
||||
$0.tags.contains(platform.rawValue)
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ class StringsFileGenerator {
|
||||
tags: [String],
|
||||
outputPath: String,
|
||||
inputFilenameWithoutExt: String) {
|
||||
|
||||
var stringsFilesContent = [String: String]()
|
||||
for lang in langs {
|
||||
stringsFilesContent[lang] = Self.generateStringsFileContent(lang: lang,
|
||||
@ -43,31 +42,6 @@ class StringsFileGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
static func writeXcStringsFiles(sections: [Section],
|
||||
langs: [String],
|
||||
defaultLang: String,
|
||||
tags: [String],
|
||||
outputPath: String,
|
||||
inputFilenameWithoutExt: String) {
|
||||
|
||||
let fileContent: String = Self.generateXcStringsFileContent(
|
||||
langs: langs,
|
||||
defaultLang: defaultLang,
|
||||
tags: tags,
|
||||
sections: sections
|
||||
)
|
||||
|
||||
let stringsFilePath = "\(outputPath)/\(inputFilenameWithoutExt).xcstrings"
|
||||
let stringsFilePathURL = URL(fileURLWithPath: stringsFilePath)
|
||||
do {
|
||||
try fileContent.write(to: stringsFilePathURL, atomically: false, encoding: .utf8)
|
||||
} catch let error {
|
||||
let error = StringiumError.writeFile(error.localizedDescription, stringsFilePath)
|
||||
print(error.description)
|
||||
Stringium.exit(withError: error)
|
||||
}
|
||||
}
|
||||
|
||||
static func generateStringsFileContent(lang: String,
|
||||
defaultLang: String,
|
||||
tags inputTags: [String],
|
||||
@ -118,117 +92,6 @@ class StringsFileGenerator {
|
||||
return stringsFileContent
|
||||
}
|
||||
|
||||
// MARK: - XcStrings Generation
|
||||
|
||||
static func generateXcStringsFileContent(langs: [String],
|
||||
defaultLang: String,
|
||||
tags inputTags: [String],
|
||||
sections: [Section]) -> String {
|
||||
let rootObject = generateRootObject(langs: langs, defaultLang: defaultLang, tags: inputTags, sections: sections)
|
||||
let file = generateXcStringsFileContentFromRootObject(rootObject: rootObject)
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
static func generateXcStringsFileContentFromRootObject(rootObject: Root) -> String {
|
||||
do {
|
||||
let encoder = JSONEncoder()
|
||||
encoder.outputFormatting = [.prettyPrinted]
|
||||
|
||||
let json = try encoder.encode(rootObject)
|
||||
|
||||
if let jsonString = String(data: json, encoding: .utf8) {
|
||||
return jsonString
|
||||
}
|
||||
|
||||
} catch {
|
||||
debugPrint("Failed to encode: \(error)")
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
static func generateRootObject(langs: [String],
|
||||
defaultLang: String,
|
||||
tags inputTags: [String],
|
||||
sections: [Section]) -> Root {
|
||||
|
||||
var xcStringDefinitionTab: [XCStringDefinition] = []
|
||||
|
||||
sections.forEach { section in
|
||||
// Check that at least one string will be generated
|
||||
guard section.hasOneOrMoreMatchingTags(tags: inputTags) else {
|
||||
return // Go to next section
|
||||
}
|
||||
|
||||
section.definitions.forEach { definition in
|
||||
var skipDefinition = false
|
||||
var isNoTranslation = false
|
||||
|
||||
var localizationTab: [XCStringLocalization] = []
|
||||
|
||||
if definition.hasOneOrMoreMatchingTags(inputTags: inputTags) == false {
|
||||
skipDefinition = true
|
||||
}
|
||||
|
||||
if definition.tags.contains(Stringium.noTranslationTag) {
|
||||
isNoTranslation = true
|
||||
}
|
||||
|
||||
if !skipDefinition {
|
||||
if isNoTranslation {
|
||||
// Search for langs in yaml
|
||||
for lang in langs {
|
||||
if let value = definition.translations[defaultLang], !value.isEmpty {
|
||||
let localization = XCStringLocalization(
|
||||
lang: lang,
|
||||
content: XCStringLocalizationLangContent(
|
||||
stringUnit: DefaultStringUnit(state: "translated", value: value)
|
||||
)
|
||||
)
|
||||
localizationTab.append(localization)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Search for langs in twine
|
||||
for (lang, value) in definition.translations where !value.isEmpty {
|
||||
|
||||
let localization = XCStringLocalization(
|
||||
lang: lang,
|
||||
content: XCStringLocalizationLangContent(
|
||||
stringUnit: DefaultStringUnit(state: "translated", value: value)
|
||||
)
|
||||
)
|
||||
|
||||
localizationTab.append(localization)
|
||||
}
|
||||
}
|
||||
|
||||
let xcStringDefinition = XCStringDefinition(
|
||||
title: definition.name,
|
||||
content: XCStringDefinitionContent(
|
||||
comment: definition.comment,
|
||||
extractionState: "manual",
|
||||
localizations: XCStringLocalizationContainer(
|
||||
localizations: localizationTab
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
xcStringDefinitionTab.append(xcStringDefinition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let xcStringContainer = XCStringDefinitionContainer(strings: xcStringDefinitionTab)
|
||||
|
||||
return Root(
|
||||
sourceLanguage: defaultLang,
|
||||
strings: xcStringContainer,
|
||||
version: "1.0"
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Extension file
|
||||
|
||||
static func writeExtensionFiles(sections: [Section],
|
||||
|
@ -84,29 +84,22 @@ class Definition {
|
||||
return (inputParameters: inputParameters, translationArguments: translationArguments)
|
||||
}
|
||||
|
||||
private func getBaseProperty(lang: String, translation: String, isStatic: Bool, comment: String?) -> String {
|
||||
private func getBaseProperty(lang: String, translation: String, isStatic: Bool) -> String {
|
||||
"""
|
||||
/// Translation in \(lang) :
|
||||
/// \(translation)
|
||||
///
|
||||
/// Comment :
|
||||
/// \(comment?.isEmpty == false ? comment! : "No comment")
|
||||
\(isStatic ? "static ": "")var \(name): String {
|
||||
NSLocalizedString("\(name)", tableName: kStringsFileName, bundle: Bundle.main, value: "\(translation)", comment: "\(comment ?? "")")
|
||||
NSLocalizedString("\(name)", tableName: kStringsFileName, bundle: Bundle.main, value: "\(translation)", comment: "")
|
||||
}
|
||||
"""
|
||||
|
||||
}
|
||||
|
||||
private func getBaseMethod(lang: String, translation: String, isStatic: Bool, inputParameters: [String], translationArguments: [String], comment: String?) -> String {
|
||||
|
||||
private func getBaseMethod(lang: String, translation: String, isStatic: Bool, inputParameters: [String], translationArguments: [String]) -> String {
|
||||
"""
|
||||
|
||||
|
||||
/// Translation in \(lang) :
|
||||
/// \(translation)
|
||||
///
|
||||
/// Comment :
|
||||
/// \(comment?.isEmpty == false ? comment! : "No comment")
|
||||
\(isStatic ? "static ": "")func \(name)(\(inputParameters.joined(separator: ", "))) -> String {
|
||||
String(format: \(isStatic ? "Self" : "self").\(name), \(translationArguments.joined(separator: ", ")))
|
||||
}
|
||||
@ -121,12 +114,7 @@ class Definition {
|
||||
}
|
||||
|
||||
// Generate property
|
||||
let property = getBaseProperty(
|
||||
lang: lang,
|
||||
translation: translation,
|
||||
isStatic: false,
|
||||
comment: self.comment
|
||||
)
|
||||
let property = getBaseProperty(lang: lang, translation: translation, isStatic: false)
|
||||
|
||||
// Generate method
|
||||
var method = ""
|
||||
@ -135,8 +123,7 @@ class Definition {
|
||||
translation: translation,
|
||||
isStatic: false,
|
||||
inputParameters: parameters.inputParameters,
|
||||
translationArguments: parameters.translationArguments,
|
||||
comment: self.comment)
|
||||
translationArguments: parameters.translationArguments)
|
||||
}
|
||||
|
||||
return property + method
|
||||
@ -150,12 +137,7 @@ class Definition {
|
||||
}
|
||||
|
||||
// Generate property
|
||||
let property = getBaseProperty(
|
||||
lang: lang,
|
||||
translation: translation,
|
||||
isStatic: true,
|
||||
comment: self.comment
|
||||
)
|
||||
let property = getBaseProperty(lang: lang, translation: translation, isStatic: true)
|
||||
|
||||
// Generate method
|
||||
var method = ""
|
||||
@ -164,8 +146,7 @@ class Definition {
|
||||
translation: translation,
|
||||
isStatic: true,
|
||||
inputParameters: parameters.inputParameters,
|
||||
translationArguments: parameters.translationArguments,
|
||||
comment: self.comment)
|
||||
translationArguments: parameters.translationArguments)
|
||||
}
|
||||
|
||||
return property + method
|
||||
@ -183,10 +164,6 @@ class Definition {
|
||||
return """
|
||||
/// Translation in \(lang) :
|
||||
/// \(translation)
|
||||
///
|
||||
/// Comment :
|
||||
/// \(comment?.isEmpty == false ? comment! : "No comment")
|
||||
|
||||
var \(name): String {
|
||||
"\(translation)"
|
||||
}
|
||||
@ -203,9 +180,6 @@ class Definition {
|
||||
return """
|
||||
/// Translation in \(lang) :
|
||||
/// \(translation)
|
||||
///
|
||||
/// Comment :
|
||||
/// \(comment?.isEmpty == false ? comment! : "No comment")
|
||||
static var \(name): String {
|
||||
"\(translation)"
|
||||
}
|
||||
|
@ -1,109 +0,0 @@
|
||||
//
|
||||
// XcString.swift
|
||||
//
|
||||
//
|
||||
// Created by Quentin Bandera on 12/04/2024.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct DynamicKey: CodingKey {
|
||||
var intValue: Int?
|
||||
init?(intValue: Int) {
|
||||
self.intValue = intValue
|
||||
self.stringValue = "\(intValue)"
|
||||
}
|
||||
|
||||
var stringValue: String
|
||||
init?(stringValue: String) {
|
||||
self.stringValue = stringValue
|
||||
}
|
||||
}
|
||||
|
||||
struct Root: Codable, Equatable {
|
||||
let sourceLanguage: String
|
||||
let strings: XCStringDefinitionContainer
|
||||
let version: String
|
||||
}
|
||||
|
||||
struct XCStringDefinitionContainer: Codable, Equatable {
|
||||
let strings: [XCStringDefinition]
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: DynamicKey.self)
|
||||
|
||||
for str in strings {
|
||||
if let codingKey = DynamicKey(stringValue: str.title) {
|
||||
try container.encode(str.content, forKey: codingKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func == (lhs: XCStringDefinitionContainer, rhs: XCStringDefinitionContainer) -> Bool {
|
||||
return lhs.strings.sorted(by: {
|
||||
$0.title < $1.title
|
||||
}) == rhs.strings.sorted(by: { $0.title < $1.title })
|
||||
}
|
||||
}
|
||||
|
||||
struct XCStringDefinition: Codable, Equatable {
|
||||
let title: String // json key -> custom encoding methods
|
||||
let content: XCStringDefinitionContent
|
||||
}
|
||||
|
||||
struct XCStringDefinitionContent: Codable, Equatable {
|
||||
let comment: String?
|
||||
let extractionState: String
|
||||
var localizations: XCStringLocalizationContainer
|
||||
|
||||
init(comment: String? = nil, extractionState: String, localizations: XCStringLocalizationContainer) {
|
||||
self.comment = comment
|
||||
self.extractionState = extractionState
|
||||
self.localizations = localizations
|
||||
}
|
||||
}
|
||||
|
||||
struct XCStringLocalizationContainer: Codable, Equatable {
|
||||
let localizations: [XCStringLocalization]
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: DynamicKey.self)
|
||||
|
||||
for loca in localizations {
|
||||
if let codingKey = DynamicKey(stringValue: loca.lang) {
|
||||
try container.encode(loca.content, forKey: codingKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func == (lhs: XCStringLocalizationContainer, rhs: XCStringLocalizationContainer) -> Bool {
|
||||
return lhs.localizations.count == rhs.localizations.count && lhs.localizations.sorted(by: { $0.lang < $1.lang }) == rhs.localizations.sorted(by: { $0.lang < $1.lang })
|
||||
}
|
||||
}
|
||||
|
||||
struct XCStringLocalization: Codable, Equatable {
|
||||
let lang: String // json key -> custom encoding method
|
||||
let content: XCStringLocalizationLangContent
|
||||
}
|
||||
|
||||
struct XCStringLocalizationLangContent: Codable, Equatable {
|
||||
let stringUnit: DefaultStringUnit
|
||||
}
|
||||
|
||||
//enum VarationOrStringUnit: Encodable {
|
||||
// case variations([Varation])
|
||||
// case stringUnit: (DefaultStringUnit)
|
||||
//
|
||||
// func encode(to encoder: any Encoder) throws {
|
||||
// if let varations {
|
||||
//
|
||||
// } else if let {
|
||||
//
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
struct DefaultStringUnit: Codable, Equatable {
|
||||
let state: String
|
||||
let value: String
|
||||
}
|
@ -43,25 +43,12 @@ struct Stringium: ParsableCommand {
|
||||
let sections = TwineFileParser.parse(options.inputFile)
|
||||
|
||||
// Generate strings files
|
||||
print(options.xcStrings)
|
||||
if !options.xcStrings {
|
||||
print("[\(Self.toolName)] Will generate strings")
|
||||
|
||||
StringsFileGenerator.writeStringsFiles(sections: sections,
|
||||
langs: options.langs,
|
||||
defaultLang: options.defaultLang,
|
||||
tags: options.tags,
|
||||
outputPath: options.stringsFileOutputPath,
|
||||
inputFilenameWithoutExt: options.inputFilenameWithoutExt)
|
||||
} else {
|
||||
print("[\(Self.toolName)] Will generate xcStrings")
|
||||
StringsFileGenerator.writeXcStringsFiles(sections: sections,
|
||||
langs: options.langs,
|
||||
defaultLang: options.defaultLang,
|
||||
tags: options.tags,
|
||||
outputPath: options.stringsFileOutputPath,
|
||||
inputFilenameWithoutExt: options.inputFilenameWithoutExt)
|
||||
}
|
||||
|
||||
// Generate extension
|
||||
StringsFileGenerator.writeExtensionFiles(sections: sections,
|
||||
|
@ -12,7 +12,7 @@ struct StringiumOptions: ParsableArguments {
|
||||
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
||||
var forceGeneration = false
|
||||
|
||||
@Argument(help: "Input files where strings are defined.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
||||
@Argument(help: "Input files where strings ared defined.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
||||
var inputFile: String
|
||||
|
||||
@Option(name: .customLong("output-path"), help: "Path where to strings file.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
||||
@ -33,9 +33,6 @@ struct StringiumOptions: ParsableArguments {
|
||||
@Option(help: "Tell if it will generate static properties or not")
|
||||
var staticMembers: Bool = false
|
||||
|
||||
@Option(help: "Tell if it will generate xcStrings file or not")
|
||||
var xcStrings: Bool = false
|
||||
|
||||
@Option(help: "Extension name. If not specified, it will generate an String extension.")
|
||||
var extensionName: String = Stringium.defaultExtensionName
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
import ToolCore
|
||||
import Foundation
|
||||
import ArgumentParser
|
||||
import Stencil
|
||||
import PathKit
|
||||
|
||||
struct ResgenSwift: ParsableCommand {
|
||||
|
||||
@ -32,6 +34,20 @@ struct ResgenSwift: ParsableCommand {
|
||||
// subcommand is not given on the command line.
|
||||
//defaultSubcommand: Twine.self
|
||||
)
|
||||
|
||||
static let projectDirectory = URL(fileURLWithPath: #file) // ProjectDir/Sources/ResgenSwift/main.swift
|
||||
.deletingLastPathComponent() // ProjectDir/Sources/ResgenSwift/
|
||||
.deletingLastPathComponent() // ProjectDir/Sources/
|
||||
.deletingLastPathComponent() // ProjectDir/
|
||||
|
||||
static let environment = Environment(
|
||||
loader: FileSystemLoader(
|
||||
paths: [
|
||||
Path("\(projectDirectory.path)/Templates/")
|
||||
]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
print(ResgenSwift.projectDirectory.path)
|
||||
ResgenSwift.main()
|
||||
|
0
Templates/Colors/json_template
Normal file
0
Templates/Colors/json_template
Normal file
21
Templates/Colors/main_template
Normal file
21
Templates/Colors/main_template
Normal file
@ -0,0 +1,21 @@
|
||||
// Generated by ResgenSwift.{{ toolName }} {{ resgenVersion }}
|
||||
{% if isSwiftUI %}
|
||||
import SwiftUI
|
||||
{% else %}
|
||||
import UIKit
|
||||
{% endif %}
|
||||
extension {{ extensionClassname }} {
|
||||
{% for color in colors %}
|
||||
{% if isSwiftUI %}
|
||||
/// Color {{ color.name }} is {{ color.light }} {{ color.light }} or {{ color.dark }} {{ color.dark }}"
|
||||
{% if isStatic %}static {% endif %}var {{ color.name }}: Color {
|
||||
Color("{{ color.name }}")
|
||||
}
|
||||
{% else %}
|
||||
/// Color {{ color.name }} is {{ color.light }} {{ color.light }} or {{ color.dark }} {{ color.dark }}"
|
||||
{% if isStatic %}static {% else %}@objc {% endif %}var {{ color.name }}: UIColor {
|
||||
UIColor(named: "{{ color.name }}")!
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
4
Templates/Colors/swiftui_template
Normal file
4
Templates/Colors/swiftui_template
Normal file
@ -0,0 +1,4 @@
|
||||
/// Color {{ color.name }} is {{ color.light }} {{ color.light }} or {{ color.dark }} {{ color.dark }}"
|
||||
{% if isStatic %}static {% endif %}var {{ color.name }}: Color {
|
||||
Color("{{ color.name }}")
|
||||
}
|
4
Templates/Colors/uikit_template
Normal file
4
Templates/Colors/uikit_template
Normal file
@ -0,0 +1,4 @@
|
||||
/// Color {{ color.name }} is {{ color.light }} {{ color.light }} or {{ color.dark }} {{ color.dark }}"
|
||||
{% if isStatic %}static {% else %}@objc {% endif %}var {{ color.name }}: UIColor {
|
||||
UIColor(named: "{{ color.name }}")!
|
||||
}
|
@ -17,8 +17,8 @@ class ImageFileParserTests: XCTestCase {
|
||||
#
|
||||
# SMAAS Support
|
||||
#
|
||||
id image_one 25 ? png
|
||||
di image_two ? 50 webp png
|
||||
id image_one 25 ?
|
||||
di image_two ? 50
|
||||
d image_three 25 ?
|
||||
d image_four 75 ?
|
||||
"""
|
||||
@ -38,7 +38,6 @@ class ImageFileParserTests: XCTestCase {
|
||||
XCTAssertEqual(firstImage!.tags, "id")
|
||||
XCTAssertEqual(firstImage!.width, 25)
|
||||
XCTAssertEqual(firstImage!.height, -1)
|
||||
XCTAssertEqual(firstImage!.imageExtensions, [.png])
|
||||
|
||||
let secondImage = parsedImages.first {
|
||||
$0.name == "image_two"
|
||||
@ -47,6 +46,5 @@ class ImageFileParserTests: XCTestCase {
|
||||
XCTAssertEqual(secondImage!.tags, "di")
|
||||
XCTAssertEqual(secondImage!.width, -1)
|
||||
XCTAssertEqual(secondImage!.height, 50)
|
||||
XCTAssertEqual(firstImage!.imageExtensions, [.png])
|
||||
}
|
||||
}
|
||||
|
@ -127,77 +127,35 @@ final class ParsedImageTests: XCTestCase {
|
||||
height: 10)
|
||||
|
||||
// When
|
||||
let property = parsedImage.generateImageContent(isVector: false)
|
||||
let property = parsedImage.contentJson
|
||||
|
||||
// Expect
|
||||
let expect = AssetContent(
|
||||
images: [
|
||||
AssetImageDescription(
|
||||
idiom: "universal",
|
||||
scale: "1x",
|
||||
filename: "\(parsedImage.name).\(OutputImageExtension.png.rawValue)"
|
||||
),
|
||||
AssetImageDescription(
|
||||
idiom: "universal",
|
||||
scale: "2x",
|
||||
filename: "\(parsedImage.name)@2x.\(OutputImageExtension.png.rawValue)"
|
||||
),
|
||||
AssetImageDescription(
|
||||
idiom: "universal",
|
||||
scale: "3x",
|
||||
filename: "\(parsedImage.name)@3x.\(OutputImageExtension.png.rawValue)"
|
||||
)
|
||||
let expect = """
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x",
|
||||
"filename" : "\(imageName).\(XcassetsGenerator.outputImageExtension)"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "\(imageName)@2x.\(XcassetsGenerator.outputImageExtension)"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x",
|
||||
"filename" : "\(imageName)@3x.\(XcassetsGenerator.outputImageExtension)"
|
||||
}
|
||||
],
|
||||
info: AssetInfo(
|
||||
version: 1,
|
||||
author: "ResgenSwift-Imagium"
|
||||
)
|
||||
)
|
||||
|
||||
XCTAssertEqual(property, expect)
|
||||
}
|
||||
|
||||
func testAssetPng() {
|
||||
// Given
|
||||
let imageName = "the_name"
|
||||
let parsedImage = ParsedImage(name: imageName,
|
||||
tags: "id",
|
||||
width: 10,
|
||||
height: 10,
|
||||
imageExtensions: [.png])
|
||||
|
||||
// When
|
||||
let property = parsedImage.generateImageContent(isVector: false)
|
||||
|
||||
// Expect
|
||||
|
||||
let expect = AssetContent(
|
||||
images: [
|
||||
AssetImageDescription(
|
||||
idiom: "universal",
|
||||
scale: "1x",
|
||||
filename: "\(parsedImage.name).\(OutputImageExtension.png.rawValue)"
|
||||
),
|
||||
AssetImageDescription(
|
||||
idiom: "universal",
|
||||
scale: "2x",
|
||||
filename: "\(parsedImage.name)@2x.\(OutputImageExtension.png.rawValue)"
|
||||
),
|
||||
AssetImageDescription(
|
||||
idiom: "universal",
|
||||
scale: "3x",
|
||||
filename: "\(parsedImage.name)@3x.\(OutputImageExtension.png.rawValue)"
|
||||
)
|
||||
],
|
||||
info: AssetInfo(
|
||||
version: 1,
|
||||
author: "ResgenSwift-Imagium"
|
||||
)
|
||||
)
|
||||
|
||||
debugPrint(property)
|
||||
debugPrint(expect)
|
||||
|
||||
XCTAssertEqual(property, expect)
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "ResgenSwift-Imagium"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
XCTAssertEqual(property.adaptForXCTest(), expect.adaptForXCTest())
|
||||
}
|
||||
}
|
||||
|
@ -100,64 +100,6 @@ final class DefinitionTests: XCTestCase {
|
||||
let expectFr = """
|
||||
/// Translation in fr :
|
||||
/// C'est la traduction francaise
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "C'est la traduction francaise", comment: "This is a comment")
|
||||
}
|
||||
"""
|
||||
|
||||
let expectEn = """
|
||||
/// Translation in en :
|
||||
/// This is the english translation
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english translation", comment: "This is a comment")
|
||||
}
|
||||
"""
|
||||
|
||||
let expectEnUs = """
|
||||
/// Translation in en-us :
|
||||
/// This is the english us translation
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english us translation", comment: "This is a comment")
|
||||
}
|
||||
"""
|
||||
|
||||
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
|
||||
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
|
||||
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
|
||||
}
|
||||
|
||||
func testGeneratedNSLocalizedStringPropertyWithEmptyComment() {
|
||||
// Given
|
||||
let definition = Definition(name: "definition_name")
|
||||
definition.tags = ["ios","iosonly","notranslation"]
|
||||
definition.comment = ""
|
||||
definition.translations = [
|
||||
"fr": "C'est la traduction francaise",
|
||||
"en": "This is the english translation",
|
||||
"en-us": "This is the english us translation"
|
||||
]
|
||||
|
||||
// When
|
||||
let propertyFr = definition.getNSLocalizedStringProperty(forLang: "fr")
|
||||
let propertyEn = definition.getNSLocalizedStringProperty(forLang: "en")
|
||||
let propertyEnUs = definition.getNSLocalizedStringProperty(forLang: "en-us")
|
||||
|
||||
// Expect
|
||||
let expectFr = """
|
||||
/// Translation in fr :
|
||||
/// C'est la traduction francaise
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "C'est la traduction francaise", comment: "")
|
||||
}
|
||||
@ -166,9 +108,6 @@ final class DefinitionTests: XCTestCase {
|
||||
let expectEn = """
|
||||
/// Translation in en :
|
||||
/// This is the english translation
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english translation", comment: "")
|
||||
}
|
||||
@ -177,9 +116,6 @@ final class DefinitionTests: XCTestCase {
|
||||
let expectEnUs = """
|
||||
/// Translation in en-us :
|
||||
/// This is the english us translation
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english us translation", comment: "")
|
||||
}
|
||||
@ -190,62 +126,6 @@ final class DefinitionTests: XCTestCase {
|
||||
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
|
||||
}
|
||||
|
||||
func testGeneratedNSLocalizedStringPropertyWithNoComment() {
|
||||
// Given
|
||||
let definition = Definition(name: "definition_name")
|
||||
definition.tags = ["ios","iosonly","notranslation"]
|
||||
definition.translations = [
|
||||
"fr": "C'est la traduction francaise",
|
||||
"en": "This is the english translation",
|
||||
"en-us": "This is the english us translation"
|
||||
]
|
||||
|
||||
// When
|
||||
let propertyFr = definition.getNSLocalizedStringProperty(forLang: "fr")
|
||||
let propertyEn = definition.getNSLocalizedStringProperty(forLang: "en")
|
||||
let propertyEnUs = definition.getNSLocalizedStringProperty(forLang: "en-us")
|
||||
|
||||
// Expect
|
||||
let expectFr = """
|
||||
/// Translation in fr :
|
||||
/// C'est la traduction francaise
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "C'est la traduction francaise", comment: "")
|
||||
}
|
||||
"""
|
||||
|
||||
let expectEn = """
|
||||
/// Translation in en :
|
||||
/// This is the english translation
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english translation", comment: "")
|
||||
}
|
||||
"""
|
||||
|
||||
let expectEnUs = """
|
||||
/// Translation in en-us :
|
||||
/// This is the english us translation
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english us translation", comment: "")
|
||||
}
|
||||
"""
|
||||
|
||||
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
|
||||
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
|
||||
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
|
||||
}
|
||||
|
||||
// MARK: - getNSLocalizedStringStaticProperty
|
||||
|
||||
func testGeneratedNSLocalizedStringStaticProperty() {
|
||||
// Given
|
||||
let definition = Definition(name: "definition_name")
|
||||
@ -266,64 +146,6 @@ final class DefinitionTests: XCTestCase {
|
||||
let expectFr = """
|
||||
/// Translation in fr :
|
||||
/// C'est la traduction francaise
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
static var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "C'est la traduction francaise", comment: "This is a comment")
|
||||
}
|
||||
"""
|
||||
|
||||
let expectEn = """
|
||||
/// Translation in en :
|
||||
/// This is the english translation
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
static var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english translation", comment: "This is a comment")
|
||||
}
|
||||
"""
|
||||
|
||||
let expectEnUs = """
|
||||
/// Translation in en-us :
|
||||
/// This is the english us translation
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
static var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english us translation", comment: "This is a comment")
|
||||
}
|
||||
"""
|
||||
|
||||
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
|
||||
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
|
||||
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
|
||||
}
|
||||
|
||||
func testGeneratedNSLocalizedStringStaticPropertyWithEmptyComment() {
|
||||
// Given
|
||||
let definition = Definition(name: "definition_name")
|
||||
definition.tags = ["ios","iosonly","notranslation"]
|
||||
definition.comment = ""
|
||||
definition.translations = [
|
||||
"fr": "C'est la traduction francaise",
|
||||
"en": "This is the english translation",
|
||||
"en-us": "This is the english us translation"
|
||||
]
|
||||
|
||||
// When
|
||||
let propertyFr = definition.getNSLocalizedStringStaticProperty(forLang: "fr")
|
||||
let propertyEn = definition.getNSLocalizedStringStaticProperty(forLang: "en")
|
||||
let propertyEnUs = definition.getNSLocalizedStringStaticProperty(forLang: "en-us")
|
||||
|
||||
// Expect
|
||||
let expectFr = """
|
||||
/// Translation in fr :
|
||||
/// C'est la traduction francaise
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
static var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "C'est la traduction francaise", comment: "")
|
||||
}
|
||||
@ -332,9 +154,6 @@ final class DefinitionTests: XCTestCase {
|
||||
let expectEn = """
|
||||
/// Translation in en :
|
||||
/// This is the english translation
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
static var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english translation", comment: "")
|
||||
}
|
||||
@ -343,63 +162,6 @@ final class DefinitionTests: XCTestCase {
|
||||
let expectEnUs = """
|
||||
/// Translation in en-us :
|
||||
/// This is the english us translation
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
static var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english us translation", comment: "")
|
||||
}
|
||||
"""
|
||||
|
||||
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
|
||||
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
|
||||
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
|
||||
}
|
||||
|
||||
func testGeneratedNSLocalizedStringStaticPropertyWithNoComment() {
|
||||
// Given
|
||||
let definition = Definition(name: "definition_name")
|
||||
definition.tags = ["ios","iosonly","notranslation"]
|
||||
definition.translations = [
|
||||
"fr": "C'est la traduction francaise",
|
||||
"en": "This is the english translation",
|
||||
"en-us": "This is the english us translation"
|
||||
]
|
||||
|
||||
// When
|
||||
let propertyFr = definition.getNSLocalizedStringStaticProperty(forLang: "fr")
|
||||
let propertyEn = definition.getNSLocalizedStringStaticProperty(forLang: "en")
|
||||
let propertyEnUs = definition.getNSLocalizedStringStaticProperty(forLang: "en-us")
|
||||
|
||||
// Expect
|
||||
let expectFr = """
|
||||
/// Translation in fr :
|
||||
/// C'est la traduction francaise
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
static var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "C'est la traduction francaise", comment: "")
|
||||
}
|
||||
"""
|
||||
|
||||
let expectEn = """
|
||||
/// Translation in en :
|
||||
/// This is the english translation
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
static var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english translation", comment: "")
|
||||
}
|
||||
"""
|
||||
|
||||
let expectEnUs = """
|
||||
/// Translation in en-us :
|
||||
/// This is the english us translation
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
static var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english us translation", comment: "")
|
||||
}
|
||||
@ -426,18 +188,12 @@ final class DefinitionTests: XCTestCase {
|
||||
let expectFr = """
|
||||
/// Translation in fr :
|
||||
/// Welcome "%@" !
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome \"%@\" !", comment: "This is a comment")
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome \"%@\" !", comment: "")
|
||||
}
|
||||
|
||||
/// Translation in fr :
|
||||
/// Welcome "%@" !
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
func definition_name(arg0: String) -> String {
|
||||
String(format: self.definition_name, arg0)
|
||||
}
|
||||
@ -462,18 +218,12 @@ final class DefinitionTests: XCTestCase {
|
||||
let expectFr = """
|
||||
/// Translation in fr :
|
||||
/// Welcome "%@" ! Your age is %d :) Your weight is %f ;-)
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome \"%@\" ! Your age is %d :) Your weight is %f ;-)", comment: "This is a comment")
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome \"%@\" ! Your age is %d :) Your weight is %f ;-)", comment: "")
|
||||
}
|
||||
|
||||
/// Translation in fr :
|
||||
/// Welcome "%@" ! Your age is %d :) Your weight is %f ;-)
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
func definition_name(arg0: String, arg1: Int, arg2: Double) -> String {
|
||||
String(format: self.definition_name, arg0, arg1, arg2)
|
||||
}
|
||||
@ -499,18 +249,12 @@ final class DefinitionTests: XCTestCase {
|
||||
let expectFr = """
|
||||
/// Translation in fr :
|
||||
/// Vous %%: %1$@ %2$@ Age: %3$d
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "Vous %%: %1$@ %2$@ Age: %3$d", comment: "This is a comment")
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "Vous %%: %1$@ %2$@ Age: %3$d", comment: "")
|
||||
}
|
||||
|
||||
/// Translation in fr :
|
||||
/// Vous %%: %1$@ %2$@ Age: %3$d
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
func definition_name(arg0: String, arg1: String, arg2: Int) -> String {
|
||||
String(format: self.definition_name, arg0, arg1, arg2)
|
||||
}
|
||||
@ -519,18 +263,12 @@ final class DefinitionTests: XCTestCase {
|
||||
let expectEn = """
|
||||
/// Translation in en :
|
||||
/// You %%: %2$@ %1$@ Age: %3$d
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
var definition_name: String {
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "You %%: %2$@ %1$@ Age: %3$d", comment: "This is a comment")
|
||||
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "You %%: %2$@ %1$@ Age: %3$d", comment: "")
|
||||
}
|
||||
|
||||
/// Translation in en :
|
||||
/// You %%: %2$@ %1$@ Age: %3$d
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
func definition_name(arg0: String, arg1: String, arg2: Int) -> String {
|
||||
String(format: self.definition_name, arg0, arg1, arg2)
|
||||
}
|
||||
@ -562,9 +300,6 @@ final class DefinitionTests: XCTestCase {
|
||||
let expectFr = """
|
||||
/// Translation in fr :
|
||||
/// C'est la traduction francaise
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
var definition_name: String {
|
||||
"C'est la traduction francaise"
|
||||
}
|
||||
@ -573,9 +308,6 @@ final class DefinitionTests: XCTestCase {
|
||||
let expectEn = """
|
||||
/// Translation in en :
|
||||
/// This is the english translation
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
var definition_name: String {
|
||||
"This is the english translation"
|
||||
}
|
||||
@ -584,9 +316,6 @@ final class DefinitionTests: XCTestCase {
|
||||
let expectEnUs = """
|
||||
/// Translation in en-us :
|
||||
/// This is the english us translation
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
var definition_name: String {
|
||||
"This is the english us translation"
|
||||
}
|
||||
@ -597,117 +326,6 @@ final class DefinitionTests: XCTestCase {
|
||||
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
|
||||
}
|
||||
|
||||
func testGeneratedRawPropertyWithEmptyComment() {
|
||||
// Given
|
||||
let definition = Definition(name: "definition_name")
|
||||
definition.tags = ["ios","iosonly","notranslation"]
|
||||
definition.comment = ""
|
||||
definition.translations = [
|
||||
"fr": "C'est la traduction francaise",
|
||||
"en": "This is the english translation",
|
||||
"en-us": "This is the english us translation"
|
||||
]
|
||||
|
||||
// When
|
||||
let propertyFr = definition.getProperty(forLang: "fr")
|
||||
let propertyEn = definition.getProperty(forLang: "en")
|
||||
let propertyEnUs = definition.getProperty(forLang: "en-us")
|
||||
|
||||
// Expect
|
||||
let expectFr = """
|
||||
/// Translation in fr :
|
||||
/// C'est la traduction francaise
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
var definition_name: String {
|
||||
"C'est la traduction francaise"
|
||||
}
|
||||
"""
|
||||
|
||||
let expectEn = """
|
||||
/// Translation in en :
|
||||
/// This is the english translation
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
var definition_name: String {
|
||||
"This is the english translation"
|
||||
}
|
||||
"""
|
||||
|
||||
let expectEnUs = """
|
||||
/// Translation in en-us :
|
||||
/// This is the english us translation
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
var definition_name: String {
|
||||
"This is the english us translation"
|
||||
}
|
||||
"""
|
||||
|
||||
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
|
||||
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
|
||||
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
|
||||
}
|
||||
|
||||
func testGeneratedRawPropertyWithNoComment() {
|
||||
// Given
|
||||
let definition = Definition(name: "definition_name")
|
||||
definition.tags = ["ios","iosonly","notranslation"]
|
||||
definition.translations = [
|
||||
"fr": "C'est la traduction francaise",
|
||||
"en": "This is the english translation",
|
||||
"en-us": "This is the english us translation"
|
||||
]
|
||||
|
||||
// When
|
||||
let propertyFr = definition.getProperty(forLang: "fr")
|
||||
let propertyEn = definition.getProperty(forLang: "en")
|
||||
let propertyEnUs = definition.getProperty(forLang: "en-us")
|
||||
|
||||
// Expect
|
||||
let expectFr = """
|
||||
/// Translation in fr :
|
||||
/// C'est la traduction francaise
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
var definition_name: String {
|
||||
"C'est la traduction francaise"
|
||||
}
|
||||
"""
|
||||
|
||||
let expectEn = """
|
||||
/// Translation in en :
|
||||
/// This is the english translation
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
var definition_name: String {
|
||||
"This is the english translation"
|
||||
}
|
||||
"""
|
||||
|
||||
let expectEnUs = """
|
||||
/// Translation in en-us :
|
||||
/// This is the english us translation
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
var definition_name: String {
|
||||
"This is the english us translation"
|
||||
}
|
||||
"""
|
||||
|
||||
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
|
||||
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
|
||||
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
|
||||
}
|
||||
|
||||
// MARK: - Raw static properties
|
||||
|
||||
func testGeneratedRawStaticProperty() {
|
||||
// Given
|
||||
let definition = Definition(name: "definition_name")
|
||||
@ -728,9 +346,6 @@ final class DefinitionTests: XCTestCase {
|
||||
let expectFr = """
|
||||
/// Translation in fr :
|
||||
/// C'est la traduction francaise
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
static var definition_name: String {
|
||||
"C'est la traduction francaise"
|
||||
}
|
||||
@ -739,9 +354,6 @@ final class DefinitionTests: XCTestCase {
|
||||
let expectEn = """
|
||||
/// Translation in en :
|
||||
/// This is the english translation
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
static var definition_name: String {
|
||||
"This is the english translation"
|
||||
}
|
||||
@ -750,118 +362,6 @@ final class DefinitionTests: XCTestCase {
|
||||
let expectEnUs = """
|
||||
/// Translation in en-us :
|
||||
/// This is the english us translation
|
||||
///
|
||||
/// Comment :
|
||||
/// This is a comment
|
||||
static var definition_name: String {
|
||||
"This is the english us translation"
|
||||
}
|
||||
"""
|
||||
|
||||
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
|
||||
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
|
||||
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
|
||||
}
|
||||
|
||||
func testGeneratedRawStaticPropertyWithEmptyComment() {
|
||||
// Given
|
||||
let definition = Definition(name: "definition_name")
|
||||
definition.tags = ["ios","iosonly","notranslation"]
|
||||
definition.comment = ""
|
||||
definition.translations = [
|
||||
"fr": "C'est la traduction francaise",
|
||||
"en": "This is the english translation",
|
||||
"en-us": "This is the english us translation"
|
||||
]
|
||||
|
||||
// When
|
||||
let propertyFr = definition.getStaticProperty(forLang: "fr")
|
||||
let propertyEn = definition.getStaticProperty(forLang: "en")
|
||||
let propertyEnUs = definition.getStaticProperty(forLang: "en-us")
|
||||
|
||||
// Expect
|
||||
let expectFr = """
|
||||
/// Translation in fr :
|
||||
/// C'est la traduction francaise
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
static var definition_name: String {
|
||||
"C'est la traduction francaise"
|
||||
}
|
||||
"""
|
||||
|
||||
let expectEn = """
|
||||
/// Translation in en :
|
||||
/// This is the english translation
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
static var definition_name: String {
|
||||
"This is the english translation"
|
||||
}
|
||||
"""
|
||||
|
||||
let expectEnUs = """
|
||||
/// Translation in en-us :
|
||||
/// This is the english us translation
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
static var definition_name: String {
|
||||
"This is the english us translation"
|
||||
}
|
||||
"""
|
||||
|
||||
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
|
||||
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
|
||||
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
|
||||
}
|
||||
|
||||
func testGeneratedRawStaticPropertyWithNoComment() {
|
||||
// Given
|
||||
let definition = Definition(name: "definition_name")
|
||||
definition.tags = ["ios","iosonly","notranslation"]
|
||||
definition.translations = [
|
||||
"fr": "C'est la traduction francaise",
|
||||
"en": "This is the english translation",
|
||||
"en-us": "This is the english us translation"
|
||||
]
|
||||
|
||||
// When
|
||||
let propertyFr = definition.getStaticProperty(forLang: "fr")
|
||||
let propertyEn = definition.getStaticProperty(forLang: "en")
|
||||
let propertyEnUs = definition.getStaticProperty(forLang: "en-us")
|
||||
|
||||
// Expect
|
||||
let expectFr = """
|
||||
/// Translation in fr :
|
||||
/// C'est la traduction francaise
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
static var definition_name: String {
|
||||
"C'est la traduction francaise"
|
||||
}
|
||||
"""
|
||||
|
||||
let expectEn = """
|
||||
/// Translation in en :
|
||||
/// This is the english translation
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
static var definition_name: String {
|
||||
"This is the english translation"
|
||||
}
|
||||
"""
|
||||
|
||||
let expectEnUs = """
|
||||
/// Translation in en-us :
|
||||
/// This is the english us translation
|
||||
///
|
||||
/// Comment :
|
||||
/// No comment
|
||||
static var definition_name: String {
|
||||
"This is the english us translation"
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user