mamakurka
mamakurka

Reputation: 500

How to autogenerate list of Localizable.strings

I'm creating swift application. It contains some of the strings in Localizable.strings file. Each time when I want to use it I need to get it by its id. At the beginning I created an enum with them but it was a little bit annoying to add it manually every time when I add new text. I tried to make this process simplier and I add new script phase to the xcode build phases. This script create for me string extension class and then read the localizable file line by line find words between quotes and convert it to the string variable. In general it looks like following:

echo "
import Foundation

extension String {

    " > Classes/Constants/StringId.swift



while IFS= read -r line;do

PREFIX="static var"
VAR_NAME=`echo $line| awk -F \" '{print $2}'`
SUFFIX_1=": String {
get {
    return String.from(core: \"$VAR_NAME\")
}}"
SUFFIX_2="\""

if [ -z "$VAR_NAME" ]
then
echo "empty"
else
echo "$PREFIX lib_$VAR_NAME $SUFFIX_1"  >> Classes/Constants/StringId.swift
fi
done < Resources/Base.lproj/Localizable.strings

Where String.from... is my internal method to get string from properly resource file (like general strings, accessibility strings or brandable strings).

As a result I have a class with following structure:

import Foundation

    extension String {


    static var lib_author_website : String {
    get {
        return String.from(core: "author_website")
    }}
    static var lib_author_name : String {
    get {
        return String.from(core: "author_name")
    }}
    static var lib_app_name : String {
    get {
        return String.from(core: "app_name")
    }}
}

And finally I can call the string like:

label.text = String.lib_app_name

It is just my idea but I needed to make all of these by myself, so I just curious if there is better or more popular solutions for it? I plan to do the same for the assets names and the storyboards but maybe there is better approach for handle this?

Upvotes: 1

Views: 7181

Answers (2)

Vasily  Bodnarchuk
Vasily Bodnarchuk

Reputation: 25294

dr_barto right. SwiftGen is a good tool to generate code from strings files.

Details

  • Xcode Version 10.3 (10G8), Swift 5

Solution

Podfile

target 'stackoverflow-46981208' do
  use_frameworks!
  pod 'SwiftGen' 
end

Run Script

TemplatePath=$PODS_ROOT/SwiftGen/templates
AppRoot=$PROJECT_DIR/stackoverflow-46981208
Resources=$AppRoot/Resources
LocalizationInput=$Resources/Localization/en.lproj/Localizable.strings
LocalizationOutput=$Resources/Localization/GeneratedStrings.swift

$PODS_ROOT/SwiftGen/bin/swiftgen strings $LocalizationInput -p $TemplatePath/strings/structured-swift4.stencil --output $LocalizationOutput;

enter image description here

Files structure

enter image description here

Localizable.strings

"Basic.Hello" = "Hello";

"Auth.SignIn.Login" = "Login";
"Auth.SignIn.Password" = "Password";

Usage

print(L10n.Basic.hello)

Generated code sample

// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length

// MARK: - Strings

// swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length
// swiftlint:disable nesting type_body_length type_name
internal enum L10n {

  internal enum Auth {
    internal enum SignIn {
      /// Login
      internal static let login = L10n.tr("Localizable", "Auth.SignIn.Login")
      /// Password
      internal static let password = L10n.tr("Localizable", "Auth.SignIn.Password")
    }
  }

  internal enum Basic {
    /// Hello
    internal static let hello = L10n.tr("Localizable", "Basic.Hello")
  }
}
// swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length
// swiftlint:enable nesting type_body_length type_name

// MARK: - Implementation Details

extension L10n {
  private static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
    // swiftlint:disable:next nslocalizedstring_key
    let format = NSLocalizedString(key, tableName: table, bundle: Bundle(for: BundleToken.self), comment: "")
    return String(format: format, locale: Locale.current, arguments: args)
  }
}

private final class BundleToken {}

Results

enter image description here

Upvotes: 5

dr_barto
dr_barto

Reputation: 6085

You can use SwiftGen to auto-generate code for type-safe access to various projects resources, amongst others also for localizable strings. It even supports placeholders inside the strings. The tool can be run standalone on the commandline or integrated into the project's build process, so that every time you compile you also get updated localization code.

Upvotes: 0

Related Questions