How do I use Twine with my Xcode Project? - objective-c

Twine looks great, but the documentation is a bit lacking, and there is no sample iOS project. I'm wondering how I would incorporate this tool into my project.
Specifically:
Is it recommended that my keys be arbitrary codes (e.g. path_not_found_error) or English words/sentences as Apple recommends (e.g. Unable to find path). The article that introduces Twine mentions how English words/sentences fall short when a single word could mean two different things (e.g. list as noun vs. a verb), but then also mentions the drawbacks of using keys: if you forget to include one, the user will see your key name (path_not_found_error) rather than the English counterpart (Unable to find path).
Say I'm writing code and I want to include a new string. What are the steps in order to do so? When following Apple's recommendation, I can simply type NSLocalizedString(#"Sample text", nil), and I am done. What is the process in order to get it working with Twine?
In their examples, they show categories such as [[General]] and [[Errors]]. How do I categorize a string?
In their examples, they show tags. what exactly are these, and how would I use them?

To generate the first version of strings.txt:
Generate Localizable.strings from all the NSLocalizedString macros in your code.
find . -name \*.m | xargs genstrings -o /tmp
It is recommended to save this in Resources/Locales/en.lproj/Localizable.strings
Create the initial, empty strings.txt file:
touch strings.txt
Populate it with the contents of Localizable.strings:
twine consume-all-string-files strings.txt Resources/Locales --developer-language en --consume-all --consume-comments
It seems that after doing this once, it's recommended that you manually modify the strings.txt file going forward.
To create a new string in your code:
Type in the string you want to use, for example:
NSString *prompt = NSLocalizableString(#"prompt_user_name", nil);
Manually add the key/value to the strings.txt file, optionally placing them in a category:
[prompt_user_name]
en = Please enter in a user name
Now when you build the project, it will generate Localizable.strings and when you run the app you will see the correct string. (Assuming you followed the Twine and Your Build Process steps.)

In their examples, they show categories such as [[General]] and [[Errors]]. How do I categorize a string?
Actually, there is no way to add sections automatically, checked their master and there is no section parser in apple strings formatter. So I suppose that the only way is to do it manually.
In their examples, they show tags. what exactly are these, and how would I use them?
This works when you have app on multiple platforms. For example you can add tags iOS and Android and then generate resources based on your tag for particular platform.

Related

Upload image diff using CTest and CDash

For running automated tests in a C++ application, I would like the application to dump an image and compare it against a baseline image. I saw several examples of this on various CDash dashboards, e.g. this one (link might not be valid for long).
https://open.cdash.org/testDetails.php?test=660365465&build=5407474
My google-fu has failed me on this one, what is the correct way to get this functionality?
The easiest way to attach ordinary files to test results is by listing those files in either the ATTACHED_FILES or ATTACHED_FILES_ON_FAIL test properties. This is not the mechanism being used here though.
According to this mailing list post, you can output special contents like that shown below to the test's stdout and it results in the named files being uploaded. The sample CDash results page you linked to follows a similar pattern as the example from the mailing list, which I've reproduced here for reference (I've made one small correction to change DifferenceImage to DifferenceImage2):
<DartMeasurement name="BaselineImage" type="text/string">Standard</DartMeasurement>
<DartMeasurementFile name="TestImage" type="image/png">C:/Users/.../Testing/Temporary/BoxWidget.png</DartMeasurementFile>
<DartMeasurementFile name="DifferenceImage2" type="image/png">C:/Users/.../Testing/Temporary/BoxWidget.diff.png</DartMeasurementFile>
<DartMeasurementFile name="ValidImage" type="image/png">C:/Users/.../VTKData/Baseline/Widgets/BoxWidget.png</DartMeasurementFile>
I've checked through the CTest source code and it scans the test output looking for <DartMeasurement> and <DartMeasurementFile> tags here and here. These are uploaded as discrete measurement items to CDash, which also looks for these particular names and presents them specially as in the example CDash links in the question.

Force a specific localization to be used for a target

I'm developing an app that, among other things, will play a large audio file (30MB).
I want to submit the app to the App Store in several countries. The audio file is different per target country, the rest of the app remains the same (Although localized).
I've created a target for each country, a bash script takes care of copying the correct audio file into compiled app based on the target, and it works great.
I've also localized the ressources (Images and Localized.strings) to make it easy to maintain.
Let's say I built my target for Sweden, I want to include only the swedish localization to force the app to always show swedish language (Which matches the audio file).
Here's the actual question:* How do I exclude all localizations from a target or force a target to ONLY use a specific localization, regardless of phone settings?
Based on your comment in answer to Lvsti (where you say the reason you're doing this is that translations in some of your languages aren't finished yet but you want to release what you have), perhaps as an alternative to deleting all the relevant localization files or messing with your build settings you can try to edit the list of languages in your XCode project? It's not per target but per project, but it might allow you to exclude languages you don't want in your build. See under Localizations in your project settings (there's a little - icon you can use to remove a language).
I think you might be able to pull it of by going to:
Target Settings => Info => Add a new row called Localizations => Add a new element to that array with the kind of language you want (I think the default is english)
I haven't tested it, just let me know if it worked.
If I understand your question, you don't actually need a localized app, or at least not a fully localized one. If that is the case, I would use a run-script build phase which is responsible for copying the appropriate non-localized but target-specific resources based on the current target. E.g. supposing you have an Audio folder in your project root with all the versions for the different languages, your script could look like:
cp "$PROJECT_DIR/Audio/$TARGETNAME.mp3" "$TARGET_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/audio.mp3"
which would e.g. copy/rename "Swedish.mp3" to "audio.mp3" directly accessible from the bundle.

Xcode: Run project with specified localization

My Cocoa project is localized in Italian (my language) and English language.
If I run it, i see everything in Italian (of course, my OS is italian!).
How can I run it to test the English localization without changing the OS language?
In the old times, Leopard and before, the get info window in Finder would let
you choose the available languages. So it was a matter of deselecting the
language that you don't want to use and it would "default" to the other.
These days you can use an utility like this one. I'd love to know what it
does behind the scenes though.
I finally found a nice solution in the cocoa-dev mailing list archives.
Apparently, you can change the default domain within the arguments passed to
your executable, and this causes the global preference to be overwritten. It
can be achieved with the -AppleLanguages flag, pass a list of the languages
in the preferred order:
~/apath/AppName.app/Contents/MacOS/AppName -AppleLanguages "(Italian, English)"
Run this from your terminal and it should give a different precedence for the
language. Notice you can also specify a single element list "(Italian)"
—makes more sense for testing purposes.
To do it within Xcode and avoid the terminal, go to the menu Product > Edit
Scheme… . Then, in your run configuration switch to the Arguments tab and
create a new one to be passed on launch. Add -AppleLanguages "(Japanese)"
text to it. Something similar to this:
Assuming you have a file that holds all the strings, swap the names of the files. Or, if you've got a it.lproj and en.lproj group in your project, just move your InfoPlist.strings (or whatever you named it) into the other group and vice versa.

Can .strings resource files be added at runtime?

I know that in Mac apps one can add .strings files to the project folder to add localizations.
Is there any way that additional localizations can be added to an app (iOS or Mac OS) without loading them from the resources bundle at compile time. Say, downloading an additional localization and storing it in /Documents on iOS?
Yes, but it's not what you think.
You can take a strings file and load it into an NSString, and then transform it into a dictionary using -[NSString propertyListFromStringsFileFormat].
This will provide you with a way to store your custom-translated strings in-memory.
As for actually using that, you'll have to define custom translation functions. IE, you can't use NSLocalizedString() and friends any more. Fortunately, genstrings (the utility used for generating strings files) lets you specify custom function names:
genstrings -s "JPLocalizedString" ...
This means that in code, you can define:
NSString* JPLocalizedString(NSString *key, NSString *comment) {
return [myLoadedStrings objectForKey:key];
}
As well as JPLocalizedStringFromTable(), JPLocalizedStringFromTableInBundle(), JPLocalizedStringWithDefaultValue(). genstrings will pick up all of those. (In other words, just because NSLocalizedString is a macro doesn't mean your version has to be)
If you do this and use these JPLocalizedString variants, then genstrings will still generate your strings files for you (providing you use the -s flag).
Once these functions are called, you can use whatever lookup mechanism you want, defaulting back to the NSLocalizedString versions if you can't find anything.
If you want to implement an alternate version of NSLocalizedString() inside your application, there are number of good strategies for that. That would allow you to modify the values used inside your application itself. But those won't work when it comes to Push Notifications.
Warning however : for iOS Push Notifications that use Localized Strings, there is no legal runtime method modify the built in strings resources that are used to translate the localized arguments sent from your server into the device's native language.
So if you want to use Localized Strings as part of Push Notifications, you must ship them in the app when you submit to the store. They can't be modified later by loading something from the server.
You should be able to achieve this by overriding NSBundle’s various pathForResource:… methods in a category. (I would assume they all go through -pathForResource:ofType:inDirectory:forLocalization:, but this isn’t documented so you can’t rely on it even if it turns out to be the case now, so you should override all of them.)
I also suggest filing an enhancement request for a clean way of overriding the lookup mechanism.
I managed to do it and I created a small repo to show how I have done it:
https://github.com/multitudes/MyLocalisationTestApp
Create a custom bundle in the documents directory.
Looking at the Apple documentation for Text: https://developer.apple.com/documentation/swiftui/text
The SwiftUI text view initializer accepts a bundle parameter.
1 - I created a custom bundle in the Documents directory.
2 - I placed programmatically the language folders the strings files inside it.
3 - When using it I pass the custom bundle and the tableName (the name of the .strings file) to the Text initialiser together with the key.
Like in SwiftUI it will be: Text(localizedStringKey, tableName: tableName, bundle: bundle)

Stopping doxygen searching for (and assuming) non-existant variables in source code

Im using doxygen outside of its design, but well within its capability. I have a bunch of essentially text files, appended with some doxygen tags. I am successfully generating doxygen output. However, somehow doxygen occasionally discovers what it assumes to be a variable, and proceeds to document it using surrounding text, causing a lot of confusing documentation. I cant see any direct relationship between these anomalies, only that they're reproducing the same output on each run, and what I can see is at least some are next to a ';' or a '='.
I only want doxygen to document what I've manually tagged. I am hoping to remove any occurrence of these anomalies, however I cannot alter existing text. I can only add doxygen tags, or alter the configuration file. Any ideas?
Many thanks.
Because in my particular case, I do not need any automatically generated documentation, only that which I have tagged with doxygen tags, setting
EXCLUDE_SYMBOLS = *
removes any instance of doxygen "finding" and documenting variables. This however may remove any ability to find any class declarations, namespaces or functions, however this is acceptable for me.