Swift CLI for strong-typing images, colors, storyboards, fonts and localizations

Related tags

Tools Shark
Overview

Shark

Build

Shark is a Swift command line tool that generates type safe enums for your images, colors, storyboards, fonts and localizations.

Because Shark reads your .xcodeproj to find these assets, the setup is extremely simple.

Motivation

Here's what a generated Shark.swift file looks like and how it is used in a codebase:

// Shark.swift
// Generated by Shark https://github.com/kaandedeoglu/Shark

import UIKit

// swiftlint:disable all
public enum Shark {
    private static let bundle: Bundle = {
        class Custom {}
        return Bundle(for: Custom.self)
    }()

    public enum I {
        public enum Button {
            public static var profile: UIImage { return UIImage(named:"profile", in: bundle, compatibleWith: nil)! }
            public static var cancel: UIImage { return UIImage(named:"cancel", in: bundle, compatibleWith: nil)! }
            public static var user_avatar: UIImage { return UIImage(named:"user_avatar", in: bundle, compatibleWith: nil)! }
        }
    }

    public enum C {
        public static var blue1: UIColor { return UIColor(named: "blue1", in: bundle, compatibleWith: nil)! }
        public static var blue2: UIColor { return UIColor(named: "blue2", in: bundle, compatibleWith: nil)! }
        public static var gray1: UIColor { return UIColor(named: "gray1", in: bundle, compatibleWith: nil)! }
        public static var gray2: UIColor { return UIColor(named: "gray2", in: bundle, compatibleWith: nil)! }
        public static var green1: UIColor { return UIColor(named: "green1", in: bundle, compatibleWith: nil)! }
        public static var green2: UIColor { return UIColor(named: "green2", in: bundle, compatibleWith: nil)! }
    }

    public enum F {
        public static func gothamBold(ofSize size: CGFloat) -> UIFont { return UIFont(name: "Gotham-Bold", size: size)! }
        public static func gothamMedium(ofSize size: CGFloat) -> UIFont { return UIFont(name: "Gotham-Medium", size: size)! }
        public static func gothamRegular(ofSize size: CGFloat) -> UIFont { return UIFont(name: "Gotham-Regular", size: size)! }
    }

    public enum L {
        public enum button {
            /// Login
            public static var login: String { return NSLocalizedString("button.login", bundle: bundle, comment: "") }

            /// Logout
            public static var logout: String { return NSLocalizedString("button.logout", bundle: bundle, comment: "") }
        }

        public enum login {
            /// Please log in to continue
            public static var title: String { return NSLocalizedString("login.title", bundle: bundle, comment: "") }

            /// Skip login and continue
            public static var skip: String { return NSLocalizedString("login.skip", bundle: bundle, comment: "") }

            public enum error {
                /// Login failed
                public static var title: String { return NSLocalizedString("login.error.title", bundle: bundle, comment: "") }

                /// Operation failed with error: %@
                public static func message(_ value1: String) -> String {
                    return String(format: NSLocalizedString("login.error.message", bundle: bundle, comment: ""), value1)
                }
            }
        }
    }
}

// At the call site
imageView.image = Shark.I.Button.profile
label.font = Shark.F.gothamBold(ofSize: 16.0)
label.text = Shark.L.login.title
view.backgroundColor = Shark.C.green1

// You can also make it prettier with typealiases
typealias I = Shark.I
typealias C = Shark.C
typealias F = Shark.F
typealias L = Shark.L

imageView.image = I.Button.profile
label.font = F.gothamBold(ofSize: 16.0)
label.text = L.login.error.message("I disobeyed my masters")
view.backgroundColor = C.green1

There are a few things to notice:

  • Image assets are namespaced by folder. For example all the images in your Assets.xcassets/Buttons folder will live under an enum called Buttons.
  • Localizations are namespaced with separators. Currently Shark uses the dot symbol . as the separator. As you can see localization keys are recursively namespaced until we get to the last component.

Installation

Brew

brew install kaandedeoglu/formulae/shark

Manually

Clone the project, then do:

> swift build -c release
> cp ./build/release/Shark /usr/local/bin

You can then verify the installation by doing

> shark --help

Setup

  • Add a new Run Script phase to your target's build phases. This build phase should ideally run before the Compile Sources phase. The script body should look like the following:

    if [ -x "$(command -v shark)" ]; then
    shark $PROJECT_FILE_PATH $PROJECT_DIR/$PROJECT_NAME/
    fi

    the if/fi block makes sure that Shark runs only if it's installed on the current machine.

  • Build your project. You should now see a file named Shark.swift in your project folder.

  • Add this file to your target. Voila! Shark.swift will be updated every time you build the project.

  • Alternatively you can do the following:

    # Write to a specific file called MyAssets.swift
    shark $PROJECT_FILE_PATH $PROJECT_DIR/$PROJECT_NAME/MyAssets.swift
    # Write to a specific file in a different folder
    shark $PROJECT_FILE_PATH $PROJECT_DIR/$PROJECT_NAME/Utility/MyAssets.swift

Options & Flags

Shark also accepts the following command line options to configure behavior

--name

By default, the top level enum everything else lives under is called - you guessed it - Shark. You can change this by using the --name flag.

 shark $PROJECT_FILE_PATH $PROJECT_DIR/$PROJECT_NAME --name Assets

--locale

By default, Shark will try to find English localizations to generate the localizations enum. If there are no English .strings file in your project, or you'd like Shark to take another localization as base, you can specify the language code with the --locale flag.

# Use Spanish localizations for generation
shark $PROJECT_FILE_PATH $PROJECT_DIR/$PROJECT_NAME --locale es

--target

In case your Xcode project has multiple application targets, you should specify which one Shark should look at by using the --target flag.

shark $PROJECT_FILE_PATH $PROJECT_DIR/$PROJECT_NAME --target MyAppTarget

--separator

Shark will split localization keys using the separator character value, and create nested enums until we hit the last element. For example, the lines login.button.positive = "Log in!"; and login.button.negative = "Go back..."; will create the following structure inside the top level localizations enum L:

public enum login {
    public enum button {
        public static var positive: String { return NSLocalizedString("login.button.positive") }
        public static var negative: String { return NSLocalizedString("login.button.negative") }
    }
}

By default, the separator is ., only single character inputs are accepted for this option.

--top-level-scope

Declares the I, C, F, L enums in the top level scope instead of nesting it in a top level Shark enum.

--help

Prints the overview, example usage and available flags to the console.

License

The MIT License (MIT)

Copyright (c) 2020 Kaan Dedeoglu

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Comments
  • Enforcement `CaseIterable` needs to be optional

    Enforcement `CaseIterable` needs to be optional

    By making all the enums CaseIterable you essentially breaking all the projects which have their resources separated in different folders, cause now all the resources of the same type are under one huge enum, instead of the nested ones. Have to fork the tool to fix it now.

    opened by 404wasfound 6
  • Make enums CaseIterable

    Make enums CaseIterable

    I'm not sure if this is actually possible, but can we make the generated enums conform to CaseIterable? The use case here is that I have a list of images in my preview assets for testing purposes, and I need to put them in a long list. Without CaseIterable, I need to manually make the array of images.

    enhancement 
    opened by denizdogan 5
  • Build error

    Build error

    PhaseScriptExecution Run\ Script\ -\ Shark /Users/gsimmons/Library/Developer/Xcode/DerivedData/CareConsult-etlsolxnmuijbhfkgvpwykbilvup/Build/Intermediates/CareConsult.build/Debug-iphonesimulator/CareConsult.build/Script-6DB712881BA9A9DD0031CBE7.sh cd /Users/gsimmons/Developer/CenseoHealth/CareConsult /bin/sh -c /Users/gsimmons/Library/Developer/Xcode/DerivedData/CareConsult-etlsolxnmuijbhfkgvpwykbilvup/Build/Intermediates/CareConsult.build/Debug-iphonesimulator/CareConsult.build/Script-6DB712881BA9A9DD0031CBE7.sh

    /Users/gsimmons/Library/Developer/Xcode/DerivedData/CareConsult-etlsolxnmuijbhfkgvpwykbilvup/Build/Intermediates/CareConsult.build/Debug-iphonesimulator/CareConsult.build/Script-6DB712881BA9A9DD0031CBE7.sh: line 2: Creating: command not found Command /bin/sh failed with exit code 127

    opened by gsimmons 5
  • Automatic preview updating paused

    Automatic preview updating paused

    Unless you run the Shark script with "For install builds only", the automatic preview of SwiftUI in Xcode keeps popping up "Automatic preview updating paused". I'm guessing this is because it detects changes to the relevant source code.

    enhancement 
    opened by denizdogan 4
  • Storyboard support

    Storyboard support

    Would it be possible to add support for enumifying Storyboards, e.g. accessing Main.storyboard as R.S.Main?

    (I'd have a go at a pull request, if you don't have the time for it – although I would need some guidance… 😄)

    opened by mickeyl 4
  • Bundle support for framework

    Bundle support for framework

    without setting bundle for the generated code, it will crash when using with framework bundles. I've just completed support for UIImage. If you agree on my solution, I'll continue with the other NSLocalizedString, UIColor,...

    opened by quangDecember 4
  • Not working with LaunchImage on xcassets

    Not working with LaunchImage on xcassets

    Hey,

    It does not works when the project has a LaunchImage. It creates the following code for LaunchImage:

    public enum LaunchImage.launchimage {
    }
    

    which causes a build time crash.

    opened by filipealva 4
  • NSDataAsset

    NSDataAsset

    Today I learned about NSDataAsset, which would come in handy for, e.g. sounds, level maps, or what not. NSDataAssets are also stored in the asset catalogue, so it might be cool to support them in shark.

    opened by mickeyl 3
  • No top-level namespace

    No top-level namespace

    I realize I can adjust the top-level namespace with the --name argument and bring the namespaces into the top level area via typealiases, but would it be possible to get rid of the top-level namespace altogether?

    opened by mickeyl 3
  • Run only, if necessary

    Run only, if necessary

    Great project. Lean and mean, no hidden magic, it just works!

    That said, is there an easy way to run it only after the .xcodeproj file has been updated?

    opened by mickeyl 2
  • Build fails due to error related to localization

    Build fails due to error related to localization

    I am running shark using the following command

    if [ -x "$(command -v shark)" ]; then
        shark "$PROJECT_FILE_PATH" "$PROJECT_DIR/$PROJECT_NAME"
    else
        echo "error: shark not installed, run command brew install kaandedeoglu/formulae/shark"
    fi
    

    It fails with following error

    Fatal error: Error raised at top level: Shark.LocalizationBuilderError.invalidLocalizableStringsFile(path: "/Users/username/app-name/app-name/app-name/Base.lproj/LaunchScreen.storyboard/en.lproj/LaunchScreen.strings"): file /BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1001.8.63.13/swift/stdlib/public/core/ErrorType.swift, line 200

    Localization is enabled for the LaunchScreen.storyboard.

    The LaunchScreen.storyboard is found at file path /Users/username/app-name/app-name/app-name/Base.lproj/LaunchScreen.storyboard.

    The LaunchScreen.strings file for English is found at file path /Users/username/app-name/app-name/app-name/en.lproj/LaunchScreen.strings and not at the file path mentioned in the error (/Users/username/app-name/app-name/app-name/Base.lproj/LaunchScreen.storyboard/en.lproj/LaunchScreen.strings)

    opened by ghost 2
  • Swift Build Plugin

    Swift Build Plugin

    With all the work on Swift Build Plugins ­– which found its way into Xcode 14 ­– we should create a Swift Build Plugin that relieves users from having to edit the Xcode build phases to run Shark.

    This would increase usability with CI/CD as well, such as that we wouldn't have to add the generated file(s) into the SCM.

    enhancement 
    opened by mickeyl 0
Releases(1.4.0)
Owner
Kaan Dedeoglu
Kaan Dedeoglu
Xcode storyboards diff and merge tool.

StoryboardMerge Storyboard diff and merge tool which: compares and merges two storyboard files, provides an automatic merge-facility, The storyboardin

null 238 Sep 12, 2022
Generate a constants file by grabbing identifiers from storyboards in a project.

sbconstants Generate a constants file by grabbing identifiers from storyboards in a project. Installation $ gem install sbconstants Usage For automate

paul.s 310 Sep 9, 2022
Automatically build and rebuild Xcode image catalogs for app icons, universal images, and more

Better asset workflow for iOS developers. Generate Xcode image catalogs for iOS / OSX app icons, universal images, and more.

Dotan J. Nahum 822 Dec 21, 2022
AVXCAssets Generator takes path for your assets images and creates appiconset and imageset for you in just one click

AVXCAssets Generator Often while developing an app, We ran into a condition when we need to scale images to each and every aspect ratios for icons and

Angel Vasa 339 Dec 6, 2022
Build native iOS, Android, and Web apps with Capacitor and Remix.run 💿

This repository holds production ready Capacitor templates for building native mobile applications using Remix. Using Capacitor, you can quickly build out a native mobile application for iOS and Android using web technology, such as Remix.

Ionic 70 Dec 30, 2022
swiftenv allows you to easily install, and switch between multiple versions of Swift.

Swift Version Manager swiftenv allows you to easily install, and switch between multiple versions of Swift. This project was heavily inspired by pyenv

Kyle Fuller 1.9k Dec 27, 2022
An adorable little framework and command line tool for interacting with SourceKit.

SourceKitten An adorable little framework and command line tool for interacting with SourceKit. SourceKitten links and communicates with sourcekitd.fr

JP Simard 2.1k Jan 5, 2023
SwiftGen is a tool to automatically generate Swift code for resources of your projects

SwiftGen SwiftGen is a tool to automatically generate Swift code for resources of your projects (like images, localised strings, etc), to make them ty

null 8.3k Jan 5, 2023
Soulful docs for Swift & Objective-C

jazzy is a command-line utility that generates documentation for Swift or Objective-C About Both Swift and Objective-C projects are supported. Instead

Realm 7.2k Jan 3, 2023
Laurine - Localization code generator written in Swift. Sweet!

Author's note: Thanks everyone for making Laurine the TOP trending Swift repository in the world - this is amazing and very heart-warming! But this is

Jiri Trecak 1.3k Dec 28, 2022
Script to support easily using Xcode Asset Catalog in Swift.

Misen Misen is a script to support using Xcode Asset Catalog in Swift. Features Misen scans sub-directories in the specified Asset Catalog and creates

Kazunobu Tasaka 123 Jun 29, 2022
An Xcode Plugin to convert Objective-C to Swift

XCSwiftr Convert Objective-C code into Swift from within Xcode. This plugin uses the Java applet of objc2swift to do the conversion. Noticed that the

Ignacio Romero Zurbuchen 338 Nov 29, 2022
Swift autocompleter for Sublime Text, via the adorable SourceKitten framework

SwiftKitten SwiftKitten is a Swift autocompleter for Sublime Text, via the adorable SourceKitten framework. Faster than XCode ! This package is new an

John Snyder 142 Sep 9, 2022
Strong typed, autocompleted resources like images, fonts and segues in Swift projects

R.swift Get strong typed, autocompleted resources like images, fonts and segues in Swift projects Why use this? It makes your code that uses resources

Mathijs Kadijk 8.9k Jan 4, 2023
Strong typed, autocompleted resources like images, fonts and segues in Swift projects

R.swift Get strong typed, autocompleted resources like images, fonts and segues in Swift projects Why use this? It makes your code that uses resources

Mathijs Kadijk 8.9k Jan 6, 2023
Color framework for Swift & Objective-C (Gradient colors, hexcode support, colors from images & more).

Swift 3 To use the Swift 3 version, add this to your Podfile (until 2.2 or higher is released): pod 'ChameleonFramework/Swift', :git => 'https://githu

Vicc Alexander 12.5k Dec 27, 2022
Keep track of accessibility settings, leverage high contrast colors, and use scalable fonts to enable users with disabilities to use your app.

Accessibility for iOS, macOS, tvOS, and watchOS ?? What's new in Capable 2.0 ?? Here are the most important changes: ?? New framework architecture and

Christoph Wendt 230 Jan 4, 2023
Random-Colors-iOS - Random colors generator app with auto layout

Random Colors Random colors generator app with auto layout Demo demo.mp4 Depende

Adem Özcan 8 Mar 23, 2022
Validate iOS, Android, and Mac localizations. Find errors in .strings, .stringsdict, and strings.xml files.

Locheck An Xcode and Android localization file validator. Make sure your .strings, .stringsdict, and strings.xml files do not have any errors! What do

Asana 73 Dec 13, 2022
Command-line utility that checks comments for localizations in iOS interface files (.xib, .storyboard)

Localizations Comments Checker It's really easy to overlook and don't add comment for localization in interface file (.storyboard or .xib). This comma

Bikemap 0 Nov 5, 2021