Localizable.strings - Why do I need to put the placeholder in the key? - objective-c

In Localizable.strings file, why is it necessary to put placeholders in the key.
Assuming you use a dot notation like;
"welcome-back.label" = "welcome back, %#"
I've seen examples where they mix placeholders and dot notation something like this;
"welcome-back %#.label" = "welcome back, %#"
^ The above might be incorrect.
But what I don't understand is why you even need the placeholder at all in the key when its just a pointer to a value.
Can someone shed light on this?
Many thanks

You don't need it in the key, it's there to make life easier for people who read the code in the future so they can easily tell that a parameter should be passed, what it's for and therefore which variable should be used. If you want to use some other specification to indicate this that's fine. If you want to make it super terse and hard to use that's also fine, just discouraged...

NSLocalizedString will replace the string on the left hand side with the string on the right hand side. The string on the right hand side must obviously be the correct string for the situation, the string on the left hand side can be anything you want. You could use keys "1", "2", "3" etc and it would work (although you would go mad).
You can improve your life as a developer with the right strategies. I tend to never use plain english text as the key, because the same English word can have many different translations (for example "key" in German can be Taste, Schlüssel, Tonart and lots of other things). Instead I write some text that describes what the text is used for.
And to avoid problems when you type in the key incorrectly, which the compiler has no chance to find, I tend to use #define statements for the keys. Much easier to keep just a list of #defines and your localizable.strings in sync, and the compiler will tell you if you misspell a #defined constant.
And I tend to use the word "format" for strings that are format strings and not used directly. So I might have in one header file
#define kWelcomeBackLabelTitleFormat #"WelcomeBackLabelTitleFormat"
and in the localizable.strings file
"WelcomeBackLabelTitleFormat" = "welcome back, %#";
(The #define saves you if you used "WelcomebackLabelTitleFormat" by mistake with a lowercase b).

Related

Pharo: customizing smart characters

The checkbox "Smart Characters" in "Code Completion" section of Settings Browser does (at least) two things:
1) It doubles some characters when typed: ', ", (, [, {
2) It enables that I can select a piece of code, press ( (i.e. Shift+9), and the selected code becomes surrounded by parentheses: (). I also can remove parentheses by pressing ( again. I also can do this with [] by pressing [ and with {} by pressing {, i.e. Shift+[.
I do not like the first of these things so I want to disable it, but I like the second thing and want to keep it. How can I achieve this? Turning off the checkbox will disable both.
P.S. I know that when the checkbox is off, adding/removing parentheses works by Cmd+Shift+9 (which is less convenient than Shift+9) and that Cmd+[ works for [], although I do not know any working shortcut for adding/removing {} when the checkbox is off.
The setting is called "Smart Characters", which should give you a clue as to where to look. Open a Finder, type in smartCharacters, and hit Enter. You should see some partial matches as well as an exact match for NECController and NECPreferences class (and the former just calls the latter). If you investigate the classes involved a bit, you'll see that smartCharacters stores a boolean, and that smartCharactersMapping returns a dictionary mapping some characters to their "counterparts", i.e. $[ to $] and so on. Now look at senders of smartCharactersMapping, and you'll see where it's being called from.
The caller you're most likely interested in would be NECController>>smartCharacterWithEvent. So put a breakpoint in that very ugly method to see what it does. You don't care about the first two cases (the editor having a selection and there not being a smart mapping), since you want to prevent the second matching character from being inserted. So the interesting bit for you is this bit:
self newSmartCharacterInsertionStringForLeft: char right: opposite
The method only has one implementor and that one sender, so it should be safe to comment out the original method and just return the "left" character, i.e.:
newSmartCharacterInsertionStringForLeft: left right: right
^String with: left
In other words, instead of creating a string with the left and right characters, and possibly spaces between them, just return a new string with the single character you typed. Might not be the most elegant way of solving this, but it should work, and should show you how to solve similar problems in the future.
(Ideally, you'll find a better solution, post it here as an alternate answer, and contribute it to the Pharo codebase - Pharo is open source, after all.)

wxStaticText inconsistently displays 'degree' character

In the same application I have two different instances of wxStaticText. Each displays an angular value expressed in degrees. I've tested both instances for font name and font encoding. They are the same for both. I've tested that both strings passed to SetLabel() are using the same character value, decimal 176. Yet one displays the 'degree' character (small circle, up high) as expected and the other instead displays an odd character I'm not familiar with. How can this be? Is there some other property of wxStaticText I need to test?
I can't explain what you're seeing because obviously two identical controls must behave in the same way, but I can tell you that using decimal 176 is not a good way to encode the degree sign, unless you explicitly use wxConvISO8859_1 to create the corresponding wxString.
It is better to use wxString::FromUTF8("\xc2\xb0") instead or, preferably, make sure that your source files are UTF-8 encoded and just use wxString::FromUTF8("°").
Arghhhh! Found it. I was assuming SetLabel() was wxStaticText::SetLabel(), inherited from the wxWindow base class. It's not. We have a wrapper class of our own around wxStaticText that I was not aware of. It's the wrapper class that is bollixing the string value.
Moral: When debugging unfamiliar code, don't make assumptions, step ALL THE WAY in.

How to properly convert to a canonical string for searching in Cocoa?

I have a string field that I know that users will want to search on later. Inspired by the WWDC 2012 Core Data Best Practices session I plan to store a normalized version of the string into a separate field so I can optimize my search predicates.
My primary concern is case insensitivity, but while I'm normalizing strings I figure that I should also normalize the unicode representation. But I want to be sure I use the right normalization form (i.e. C,D,KC or KD). And does it matter whether I convert to lowercase first? (Localization is not my strong suit.)
So:
What are the proper methods to call to do the search normalization of the NSString?
What would be the optimal way to make sure the normalized version is stored.
I will post my first attempt as an answer, but I'd love to hear where I am wrong, other suggestions, or improvements. (Unfortunately while they showed the search predicates in that video, I don't think they showed the code from the session.)
For the use case you describe, it doesn't matter whether you pick precomposed or decomposed (C or D; although you will save a bit of space with precomposed), but think carefully about whether you want canonical or compatibility (K forms). TR15 has a nice figure that summarises the differences (Figure 6):
That is: if someone searches for "ſ" (a 'long s') do you want to match "s" (and vice versa)? These are regarded as "formatting distinctions", so you shouldn't replace the text the user enters with these forms (as you lose data), but you may want to ignore them when searching.
With regard to a case-insensitive comparison, it's not enough to simply make both strings lowercase and compare them. It will work for English, but there are languages where the mapping between lower and uppercase (if such a distinction even exists) is no so clear. The W3C wiki has a nice summary of these "case folding" issues. Unfortunately, you can't optimise this in your storage by keeping the data in one "case", you can only do a proper comparison when you know both strings and the locale.
Luckily, when working with an NSString it's -compare:options:range:locale: lets you specify an NSCaseInsensitiveSearch option and the locale (if you know it), which will handle these case folding problems for you (also take a look at NSDiacriticInsensitiveSearch and NSWidthInsensitiveSearch to see if you want to be agnostic about those differences too).
What I currently plan to do is override the setter for the field, like so:
- (void)setName:(NSString *)value
{
[self willChangeValueForKey:#"name"];
[self setPrimitiveValue:value forKey:#"name"];
[self didChangeValueForKey:#"name"];
//Store normalized for for searching
[self willChangeValueForKey:#"searchName"];
[self setPrimitiveValue:[[value lowercaseStringWithLocale:[NSLocale currentLocale]] decomposedStringWithCompatibilityMapping] forKey:#"searchName"];
[self didChangeValueForKey:#"searchName"];
}
I also made the searchName property read-only.

Trailing Ampersand in VB.NET hexadecimal?

This should be an easy one for folks. Google's got nothing except content farms linking to one blurb, and that's written in broken English. So let's get this cleared up here where it'll be entombed for all time.
What's the trailing ampersand on VB hexadecimal numbers for? I've read it forces conversion to an Int32 on the chance VB wants to try and store as an Int16. That makes sense to me. But the part I didn't get from the blurb was to always use the trailing ampersand for bitmasks, flags, enums, etc. Apparantly, it has something to do with overriding VB's fetish for using signed numbers for things internally, which can lead to weird results in comparisons.
So to get easy points, what are the rules for VB.Net hexadecimal numbers, with and without the trailing ampersand? Please include the specific usage in the case of bitmasks/flags and such, and how one would also use it to force signed vs. unsigned.
No C# please :)
Vb.net will regard "&h"-notation hex constants in the range from 0x80000000-0xFFFFFFFF as negative numbers unless the type is explicitly specified as UInt32, Int64, or UInt64. Such behavior might be understandable if the numbers were written with precisely eight digits following the "&", but for some reason I cannot fathom, vb.net will behave that way even if the numbers are written with leading zeroes. In present versions of VB, one may force the number to be evaluated correctly by using a suffix of "&" suffix (Int64), "L" (Int64), "UL" (UInt64), or "UI" (UInt32). In earlier versions of VB, the "problem range" was 0x8000-0xFFFF, and the only way to force numbers in that range to be evaluated correctly (as a 32-bit integer, which was then called a "Long") was a trailing ampersand.
Visual Basic has the concept of Type Characters. These can be used to modify variable declarations and literals, although I'd not recommend using them in variable declarations - most developers are more familiar these days with As. E.g. the following declarations are equivalent:
Dim X&
Dim X As Long
But personally, I find the second more readable. If I saw the first, I'd actually have to go visit the link above, or use Intellisense, to work out what the variable is (not good if looking at the code on paper).

How to Parse Some Wiki Markup

Hey guys, given a data set in plain text such as the following:
==Events==
* [[312]] – [[Constantine the Great]] is said to have received his famous [[Battle of Milvian Bridge#Vision of Constantine|Vision of the Cross]].
* [[710]] – [[Saracen]] invasion of [[Sardinia]].
* [[939]] – [[Edmund I of England|Edmund I]] succeeds [[Athelstan of England|Athelstan]] as [[King of England]].
*[[1275]] – Traditional founding of the city of [[Amsterdam]].
*[[1524]] – [[Italian Wars]]: The French troops lay siege to [[Pavia]].
*[[1553]] – Condemned as a [[Heresy|heretic]], [[Michael Servetus]] is [[burned at the stake]] just outside [[Geneva]].
*[[1644]] – [[Second Battle of Newbury]] in the [[English Civil War]].
*[[1682]] – [[Philadelphia]], [[Pennsylvania]] is founded.
I would like to end up with an NSDictionary or other form of collection so that I can have the year (The Number on the left) mapping to the excerpt (The text on the right). So this is what the 'template' is like:
*[[YEAR]] – THE_TEXT
Though I would like the excerpt to be plain text, that is, no wiki markup so no [[ sets. Actually, this could prove difficult with alias links such as [[Edmund I of England|Edmund I]].
I am not all that experienced with regular expressions so I have a few questions. Should I first try to 'beautify' the data? For example, removing the first line which will always be ==Events==, and removing the [[ and ]] occurrences?
Or perhaps a better solution: Should I do this in passes? So for example, the first pass I can separate each line into * [[710]] and [[Saracen]] invasion of [[Sardinia]]. and store them into different NSArrays.
Then go through the first NSArray of years and only get the text within the [[]] (I say text and not number because it can be 530 BC), so * [[710]] becomes 710.
And then for the excerpt NSArray, go through and if an [[some_article|alias]] is found, make it only be [[alias]] somehow, and then remove all of the [[ and ]] sets?
Is this possible? Should I use regular expressions? Are there any ideas you can come up with for regular expressions that might help?
Thanks! I really appreciate it.
EDIT: Sorry for the confusion, but I only want to parse the above data. Assume that that's the only type of markup that I will encounter. I'm not necessarily looking forward to parsing wiki markup in general, unless there is already a pre-existing library which does this. Thanks again!
This code assumes you are using RegexKitLite:
NSString *data = #"* [[312]] – [[Constantine the Great]] is said to have received his famous [[Battle of Milvian Bridge#Vision of Constantine|Vision of the Cross]].\n\
* [[710]] – [[Saracen]] invasion of [[Sardinia]].\n\
* [[939]] – [[Edmund I of England|Edmund I]] succeeds [[Athelstan of England|Athelstan]] as [[King of England]].\n\
*[[1275]] – Traditional founding of the city of [[Amsterdam]].";
NSString *captureRegex = #"(?i)(?:\\* *\\[\\[)([0-9]*)(?:\\]\\] \\– )(.*)";
NSRange captureRange;
NSRange stringRange;
stringRange.location = 0;
stringRange.length = data.length;
do
{
captureRange = [data rangeOfRegex:captureRegex inRange:stringRange];
if ( captureRange.location != NSNotFound )
{
NSString *year = [data stringByMatching:captureRegex options:RKLNoOptions inRange:stringRange capture:1 error:NULL];
NSString *textStuff = [data stringByMatching:captureRegex options:RKLNoOptions inRange:stringRange capture:2 error:NULL];
stringRange.location = captureRange.location + captureRange.length;
stringRange.length = data.length - stringRange.location;
NSLog(#"Year:%#, Stuff:%#", year, textStuff);
}
}
while ( captureRange.location != NSNotFound );
Note that you really need to study up on RegEx's to build these well, but here's what the one I have is saying:
(?i)
Ignore case, I could have left that out since I'm not matching letters.
(?:\* *\[\[)
?: means don't capture this block, I escape * to match it, then there are zero or more spaces (" *") then I escape out two brackets (since brackets are also special characters in a regex).
([0-9]*)
Grab anything that is a number.
(?:\]\] \– )
Here's where we ignore stuff again, basically matching " – ". Note any "\" in the regex, I have to add another one to in the Objective-C string above since "\" is a special character in a string... and yes that means matching a regex escaped single "\" ends up as "\\" in an Obj-C string.
(.*)
Just grab anything else, by default the RegEX engine will stop matching at the end of a line which is why it doesn't just match everything else. You'll have to add code to strip out the [[LINK]] stuff from the text.
The NSRange variables are used to keep matching through the file without re-matching original matches. So to speak.
Don't forget after you add the RegExKitLite class files, you also need to add the special linker flag or you'll get lots of link errors (the RegexKitLite site has installation instructions).
I'm no good with regular expressions, but this sounds like a job for them. I imagine a regex would sort this out for you quite easily.
Have a look at the RegexKitLite library.
If you want to be able to parse Wikitext in general, you have a lot of work to do. Just one complicating factor is templates. How much effort do you want to go to cope with these?
If you're serious about this, you probably should be looking for an existing library which parses Wikitext. A brief look round finds this CPAN library, but I have not used it, so I can't cite it as a personal recommendation.
Alternatively, you might want to take a simpler approach and decide which particular parts of Wikitext you're going to cope with. This might be, for example, links and headings, but not lists. Then you have to focus on each of these and turn the Wikitext into whatever you want that to look like. Yes, regular expressions will help a lot with this bit, so read up on them, and if you have specific problems, come back and ask.
Good luck!