25

genstrings works well to extract localizable content from .m file as,

find . -name \*.m | xargs genstrings -o en.lproj

But, not working for .swift file as,

find . -name \*.swift | xargs genstrings -o en.lproj
BaSha
  • 2,356
  • 3
  • 21
  • 38

7 Answers7

36

The genstrings tool works fine with swift as far as I am concerned. Here is my test:

// MyClass.swift
let message = NSLocalizedString("This is the test message.", comment: "Test")

then, in the folder with the class

# generate strings for all swift files (even in nested directories)
$ find . -name \*.swift | xargs genstrings -o .

# See results
$ cat Localizable.strings
/* Test */
"This is the test message." = "This is the test message.";
$
nacho4d
  • 43,720
  • 45
  • 157
  • 240
Mundi
  • 79,884
  • 17
  • 117
  • 140
  • 4
    I see, genstrings tracks NSLocalizedString, but I have used string extension like localizedString(). So my string becomes "This is the test message.".localizedString() and that's why it is not being tracked – BaSha Oct 13 '14 at 20:15
  • 6
    Well, you know what to do. Your problem can be solved with one smart global text replace operation. Start by ticking the checkmark above ;-). – Mundi Oct 14 '14 at 06:51
  • 3
    note: `genstrings` does not work for any long-form (arguably best practice) usage: `NSLocalizedString("checkout-okbtn", value: "Ok", comment: "in cart checkout, the button that pays")` [radar issue](https://openradar.appspot.com/22133811) – SimplGy Nov 08 '15 at 22:15
  • I also (just) found out that genstrings does _not_ work correctly with my Swift files in a mixed Objective-C/Swift project! I am most definitely using `NSLocalizedString` with string literals only. For example, this message is not found: `localizedName = NSLocalizedString("Popular Now", comment: "Name of the menu item to select content that is popular now")` -- This is a really big deal. I must find a solution for this a.s.a.p. I'll be looking into philipp's recommendation to try out https://github.com/KeepSafe/genstrings_swift – Erik van der Neut Mar 17 '16 at 23:27
  • 2
    Wait, I just realize why. I'm running a genstrings command where I'm only looking for *.m files. Let me see if I can alter that to find both *.m and *.swift in one go... – Erik van der Neut Mar 17 '16 at 23:37
  • 2
    Yes, working fine for both Objective-C and Swift in my mixed project now I changed the command to the following: `cd ~/Workspace/ios-ecentral-app/ECentral/;find ./ -type f \( -iname \*.m -o -iname \*.swift \) | xargs genstrings -o ECentral/localization/en.lproj/'` – Erik van der Neut Mar 18 '16 at 00:01
5

I believe genstrings works as intended, however Apple's xargs approach to generate strings from all your project's files is flawed and does not properly parse paths containing spaces.

That might be the reason why it's not working for you.

Try using the following:

find . -name \*.swift | tr '\n' '\0' | xargs -0 genstrings -o .

m_katsifarakis
  • 1,777
  • 1
  • 21
  • 27
4

We wrote a command line tool that works for Swift files and merges the result of apples genstrings tool. It allows for key and value in NSLocalizedString

https://github.com/KeepSafe/genstrings_swift

philipp
  • 4,133
  • 1
  • 36
  • 35
  • philipp, I have a project that is a mix of Objective-C and Swift. I have found that the `genstrings` tool only finds the message from the Objective-C source code. This genstrings_swift tool, can it be run on a mixed-code project like mine and find all the messages in one go, or do I need to follow a sequence of steps? – Erik van der Neut Mar 17 '16 at 23:34
  • This is the genstrings command I am using now, by the way: `cd ~/Workspace/ios-ecentral-app/ECentral/;find . -name \*.m | xargs genstrings -o ECentral/localization/en.lproj/` – Erik van der Neut Mar 17 '16 at 23:35
  • Oh wait... doh! I should edit that command to include *.swift...! – Erik van der Neut Mar 17 '16 at 23:36
  • Okay, fixed by changing my alias to the following: `alias genstringsECentral='cd ~/Workspace/ios-ecentral-app/ECentral/;find ./ -type f \( -iname \*.m -o -iname \*.swift \) | xargs genstrings -o ECentral/localization/en.lproj/'` -- works like a charm now. – Erik van der Neut Mar 17 '16 at 23:59
2

There's an alternative tool called SwiftGenStrings

Hello.swift

NSLocalizedString("hello", value: "world", comment: "Hi!")

SwiftGenStrings:

$ SwiftGenStrings Hello.swift 

/* Hi! */
"hello" = "world";

Apple genstrings:

$ genstrings Hello.swift

Bad entry in file Hello.swift (line = 1): Argument is not a literal string.

Disclaimer: I worked on SwiftGenStrings.

Juraj Blahunka
  • 17,913
  • 6
  • 34
  • 52
0

There is a similar question here: How to use genstrings across multiple directories?

find ./ -name "*.m" -print0 | xargs -0 genstrings -o en.lproj
AS Mackay
  • 2,831
  • 9
  • 19
  • 25
0

The issue I was having with find/genstrings was twofold:

  1. When it reached folder names with spaces (generated by the output of find), it would exit with an error
  2. When it reached the file where I had my custom routine defined, it was giving me an error when trying to parse my actual function definition

To fix both those problems I'm using the following:

find Some/Path/ \( -name "*.swift" ! -name "MyExcludedFile.swift" \) | sed "s/^/'/;s/$/'/" | xargs genstrings -o . -s MyCustomLocalizedStringRoutine

To summarize, we use the find command to both find and exclude your Swift files, then pipe the results into the sed command which will wrap each file path in quotes, then finally pipe that result into the genstrings command

Christian Gossain
  • 5,942
  • 12
  • 53
  • 85
0

Xcode now includes a powerful tool for extracting localizations.

Just select your project on the left then Editor menu >> Export localizations.

You'll get a folder with all the text in your files as well as the Localizable.strings and InfoPlist.strings

More details here: https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LocalizingYourApp/LocalizingYourApp.html

ahbou
  • 4,710
  • 23
  • 36