Issue with genstrings for Swift file - objective-c

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

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.";
$

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 .

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

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.

There is a similar question here:
How to use genstrings across multiple directories?
find ./ -name "*.m" -print0 | xargs -0 genstrings -o en.lproj

The issue I was having with find/genstrings was twofold:
When it reached folder names with spaces (generated by the output of find), it would exit with an error
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

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

Related

How does cmake print the path of the header file of the library the project depends on?

I want cmake to output the path of the header file of the library that the project depends on, and give it to ctags to generate tags.
I have tried to generate tags of all header files of the system directly: ctags -R /usr/include, but the size of the generated tags file is 190MB, which is too large.
For example, if libcurl is used in the project, then let cmake output /usr/include/curl, and then ctags can ctags -R /usr/include/curl.
I looked at cmake --help, but didn't find what I was looking for. How can I achieve this?
Generate compile_commands.json. Parse compile_commands.json, extract all "command": keys, extract all -I<this paths> include paths from compile commands, interpret them relative to build directory. sort -u the list.
$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ...
$ jq -r '.[] | .command' "$builddir"/compile_commands.json |
grep -o -- '-I[^ ]*' |
sed 's/^-I//' |
sort -u |
( cd "$builddir" && xargs -d '\n' readlink -f ) |
sort -u

Makefile and use of $$

So I have a Makefile in which I have the follwoing code that I try to understand:
for file_exe in `find . -name "zip_exe-*"`; do \
./$${file_exe} -d $(UNZIP_PATH)/lib; \
done
As I understand this piece of code will try to find some executable zip and the extract those zip files to a locations. But what puzzles me is how $${file_exe} is working. Why is the double $$ needed? I guess it has something to do with the fact that some bash commands are running from a makefile, but I can't explain to myself why the $$ is needed and a simple $ does not work since this command is running a sub-shell anyway.
Make needs to distinguish whether you want a $ to use as introducing a make-variable reference, such as ${FOOBAR} or as a plain $ passed on to the shell. The make specification (Section Macros) says that to do the latter, you must use $$ which is replaced by a single $ and passed to the shell. In effect, your snippet reads as
for file_exe in `find . -name "zip_exe-*"`; do \
./${file_exe} -d some/unzip/path/lib; \
done
to the shell.
Style note: Iterating over file lists created by backticks is considered bad style, since it may overflow the ARG_MAX limit. Better to read the file names one-by-one with
find . -name "zip_exe-*" | \
while read -r file_exe; do \
./${file_exe} -d some/unzip/path/lib; \
done

How can I find ".dat" within all *.mk files?

I am trying to grep for the .dat string in all my *.mk files using the below command. I am wondering if this is right, because it doesn't give me any output.
find . -name "*.mk" | grep *.dat
No it's not right, there are a couple of issues: 1) you seem to be supplying grep with a glob pattern, 2) the pattern is not quoted and will be expanded by the shell before grep ever sees it, 3) you're grep'ing through filenames, not file contents.
To address 1), use Basic Regular Expression, the equivalent here would be .*\.dat or just .dat. 2) is a matter of using single or double-quotes. 3) find returns filenames, so if you want grep to operate on each of those files either use the -exec flag for find or use xargs. All these taken together:
find . -name '*.mk' | xargs grep '.dat'
Use Find's Exec Flag
You don't really need a pipeline here, and can bypass the need for xargs. Use the following invocation to perform a fixed-string search (which is generally faster than a regex match) on each file found by the standard find command:
find . -name '*.mk' -exec grep -F .dat {} \;
If you're using GNU find, you can use this syntax instead to avoid the process overhead of multiple calls to grep:
find . -name '*.mk' -exec grep -F .dat {} +
Use xargs:
find . -name "*.mk"| xargs grep '\.dat'
Using exec option in find command this way:
find . -name "*.mk" -exec grep ".dat" \{\} \;

Plugin for Task Management in xcode

Is there any plugin for task management ( bug tracking, issues) to use with xcode? Or there's any plugin api that one can create plugins for it?
There really isnt anything that I know of that is as good as mylyn to intergrate with bugzilla or trac. If you found anything, please let me know!
The best way I know of to document issues or things is to put a //TODO: or //FIXME: in your code. Then when Xcode compiles you can run a local shell script to post warnings for you
Its here: (Targets --> --> BUILD PHASES --> Run Scripts (See Screenshot)
Put this script at the end of your Build Phases :
KEYWORDS="FIXME|TODO:|FIXME:|\?\?\?:|\!\!\!:"
find ${SRCROOT} \( -name "*.h" -or -name "*.m" \) -print0 | \
xargs -0 egrep --with-filename --line-number --only-matching "($KEYWORDS).*\$" | \
perl -p -e "s/($KEYWORDS)/ warning: \$1/"
Lastly there is the infamous
#pragma mark YOURTEXTHERE
Good Luck!
Here is a wishlist of things people want: https://stackoverflow.com/questions/2025605/wishlist-for-objective-c-ide-xcode
Screenshot:
I've been using the Run Script build phase for a while now and modified it so the generated build warnings directly link to the file and line where the keyword has been found.
The solution is just to print a line which matches the ones Xcode knows how to parse:
{filename}:{line}:{character}: warning: {The content of the warning}.
So the script looks like that:
KEYWORDS="FIXME|TODO:|FIXME:|\?\?\?:|\!\!\!:\#todo\#warning"
find "${SRCROOT}" \( -name "*.h" -or -name "*.m" \) -exec egrep -Hno "($KEYWORDS).*\$" {} \; | \
sed -e 's/^\([^:]\{1,\}\):\([0-9]\{1,\}\):\(.*\)$/\1:\2:1: warning: \3/'
Note that I also included #todo and #warning in the keywords as I often use javadoc/doxygen comments.
Bertrand
I made a Xcode plugin for this --> http://github.com/trawor/XToDo

How do I handle spaces in a script that uses the results of find in a for loop?

I am trying to write a simple command that searches through a music directory for all files of a certain type and copies them to a new directory. I would be fine if the files didn't have spaces.
I'm using a script from the following question, but it fails for spaces:
bash script problem, find , mv tilde files created by gedit
Any suggestions on how I can handle spaces, once I'm satisfied that all the files are being listed, I'll change echo to cp
for D in `find . -name "*.wma*"`; do echo "${D}"; done
You probably want to do this instead:
find . -name *.wma -exec echo "{}" \;