Skip to content

Commit

Permalink
Added string localization scripts and l10n support to most Obj-C code…
Browse files Browse the repository at this point in the history
…; added some locale detection heuristics on startup

git-svn-id: https://svn.r-project.org/R-packages/trunk/Mac-GUI@1048 694ef91d-65df-0310-b7bb-92e67a308ead
  • Loading branch information
s-u committed Feb 9, 2005
1 parent ead5ceb commit 107c81f
Show file tree
Hide file tree
Showing 16 changed files with 221 additions and 36 deletions.
3 changes: 2 additions & 1 deletion AMPrefs/AMPreferenceWindowController.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// Copyright (c) 2003 Andreas Mayer. All rights reserved.
//

#import "../RGUI.h" /* for NLS nacro */
#import "AMPreferenceWindowController.h"
#import "AMPrefPaneProtocol.h"
#import "AMPrefPaneIcon.h"
Expand Down Expand Up @@ -513,7 +514,7 @@ - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString
[result setAction:@selector(toolbarShowAll)];
[result setEnabled:YES];
[result setImage:[NSImage imageNamed:@"Prefs"]];
[result setLabel:NSLocalizedString(@"Show All", @"")];
[result setLabel:NLS(@"Show All")];
}
} else if (pane = [prefPanes objectForKey:itemIdentifier]) {
if (result = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier]) {
Expand Down
7 changes: 4 additions & 3 deletions HelpManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
* Suite 330, Boston, MA 02111-1307 USA.
*/

#import "RGUI.h"
#import "HelpManager.h"
#import "RController.h"
#import "REngine/REngine.h"
Expand Down Expand Up @@ -62,8 +63,8 @@ - (IBAction)runHelpSearch:(id)sender
NSString *hlp = [NSString stringWithFormat:@"as.character(help(\"%@\", htmlhelp=TRUE))", [sender stringValue]];
RSEXP *x = [re evaluateString:hlp];
if ((x==nil) || ([x string]==NULL)) {
NSString *topicString = [[[NSString alloc] initWithString: @"Topic: "] stringByAppendingString:[sender stringValue]];
NSRunInformationalAlertPanel(@"Can't find help for topic", topicString, @"OK", nil, nil);
NSString *topicString = [[[NSString alloc] initWithString: NLS(@"Topic: ")] stringByAppendingString:[sender stringValue]];
NSRunInformationalAlertPanel(NLS(@"Can't find help for topic"), topicString, NLS(@"OK"), nil, nil);
return;
}
NSString *url = [x string];
Expand Down Expand Up @@ -127,7 +128,7 @@ - (void)showHelpFor:(NSString *)topic
RSEXP *x= [re evaluateString:[NSString stringWithFormat:@"as.character(help(%@, htmlhelp=TRUE))",topic]];
if ((x==nil) || ([x string]==NULL)) {
NSString *topicString = [[[NSString alloc] initWithString: @"Topic: "] stringByAppendingString:topic];
NSRunInformationalAlertPanel(@"Can't find help for topic", topicString, @"OK", nil, nil);
NSRunInformationalAlertPanel(NLS(@"Can't find help for topic"), topicString, NLS(@"OK"), nil, nil);
return;
}

Expand Down
2 changes: 2 additions & 0 deletions LANGUAGES
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
de
it
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
NEWS

Last update: 2005-02-05 [SU]
* Added localization in all Obj-C code; updated l10n scripts
* Added scripts for localization of Obj-C code

Last update: 2005-02-03 [RG]
* Added simple line number support in source editor.
* Fixed some issues around deleteBackward in editor
Expand Down
4 changes: 2 additions & 2 deletions PrefPanes/EditorPrefPane.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
* Suite 330, Boston, MA 02111-1307 USA.
*/


#import "../RGUI.h"
#import "EditorPrefPane.h"
#import "../RController.h"
#import "../Tools/Authorization.h"
Expand Down Expand Up @@ -240,7 +240,7 @@ - (IBAction) changeEditor:(id)sender;
int answer;
NSOpenPanel *sp;
sp = [NSOpenPanel openPanel];
[sp setTitle:@"Select editor application"];
[sp setTitle:NLS(@"Select editor application")];
answer = [sp runModalForDirectory:@"/Applications" file:nil types:nil];
if(answer == NSOKButton) {
[Preferences setKey:externalEditorNameKey withObject:[sp filename]];
Expand Down
4 changes: 2 additions & 2 deletions PrefPanes/MiscPrefPane.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
* Suite 330, Boston, MA 02111-1307 USA.
*/


#import "../RGUI.h"
#import "MiscPrefPane.h"
#import "../RController.h"
#import "../Tools/Authorization.h"
Expand Down Expand Up @@ -181,7 +181,7 @@ - (IBAction) chooseWorkingDir:(id)sender {
op = [NSOpenPanel openPanel];
[op setCanChooseDirectories:YES];
[op setCanChooseFiles:NO];
[op setTitle:@"Choose Initial Working Directory"];
[op setTitle:NLS(@"Choose Initial Working Directory")];

answer = [op runModalForDirectory:[workingDir stringValue] file:nil types:[NSArray arrayWithObject:@""]];

Expand Down
11 changes: 6 additions & 5 deletions Quartz/QuartzDevice.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

/* QuartzDevice.m */


#import "../RGUI.h"
#import "../REngine/RSEXP.h"
#import "../REngine/REngine.h"

Expand Down Expand Up @@ -346,7 +346,7 @@ static Rboolean RQuartz_Open(NewDevDesc *dd, QuartzDesc *xd, char *dsp,
}


[RQuartz changeDocumentTitle: newDocument Title:@"New Quartz Device"];
[RQuartz changeDocumentTitle: newDocument Title:NLS(@"New Quartz Device")];
// xd->topLeftPoint = computeTopLeftCornerForDevNum(0);
// [[newDocument getDeviceWindow] setFrame:
// NSMakeRect(xd->topLeftPoint.x, xd->topLeftPoint.y, xd->windowWidth, xd->windowHeight) display:NO];
Expand Down Expand Up @@ -412,15 +412,15 @@ as computed by computeTopLeftCornerForDevNum(devnum-1) and rect the actuals.
xd->topLeftPoint = computeTopLeftCornerForDevNum(devnum-1);
[xd->DevWindow setFrameTopLeftPoint:xd->topLeftPoint];
}
[RQuartz changeDocumentTitle: xd->QuartzDoc Title:[NSString stringWithFormat:@"Quartz (%d) - Active",devnum+1]];
[RQuartz changeDocumentTitle: xd->QuartzDoc Title:[NSString stringWithFormat:NLS(@"Quartz (%d) - Active"),devnum+1]];

}

static void RQuartz_Deactivate(NewDevDesc *dd)
{
int devnum = devNumber((DevDesc *)dd);
QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific;
[RQuartz changeDocumentTitle: xd->QuartzDoc Title:[NSString stringWithFormat:@"Quartz (%d) - Inactive",devnum+1]];
[RQuartz changeDocumentTitle: xd->QuartzDoc Title:[NSString stringWithFormat:NLS(@"Quartz (%d) - Inactive"),devnum+1]];
}

static void RQuartz_Size(double *left, double *right,
Expand Down Expand Up @@ -915,7 +915,8 @@ static Rboolean RQuartz_Locator(double *x,double *y,NewDevDesc*dd){
return 0;
break;
default:
NSLog(@"Unknown event from locator");
// don't bark - it may be other button thus the action may be ok
//NSLog(@"Unknown event from locator");
return 0;
break;
}
Expand Down
3 changes: 2 additions & 1 deletion Quartz/RDeviceView.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
* Suite 330, Boston, MA 02111-1307 USA.
*/

#import "../RGUI.h"
#import "RDeviceView.h"
#import "RQuartz.h"
#import "../RController.h"
Expand Down Expand Up @@ -139,7 +140,7 @@ - (void)drawRect:(NSRect)aRect

if ([self inLiveResize])
{
NSString *str = [NSString stringWithFormat: @"Resizing to %g x %g",
NSString *str = [NSString stringWithFormat: NLS(@"Resizing to %g x %g"),
frame.size.width, frame.size.height];
drawStringInRect(frame, str, 20);
return;
Expand Down
4 changes: 2 additions & 2 deletions Quartz/RQuartz.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
* Suite 330, Boston, MA 02111-1307 USA.
*/


#import "../RGUI.h"
#import "RQuartz.h"
#import "../RController.h"
#import "RDeviceView.h"
Expand Down Expand Up @@ -196,7 +196,7 @@ - (IBAction)saveDocument:(id)sender
NSSavePanel *sp;
sp = [NSSavePanel savePanel];
[sp setRequiredFileType:@"pdf"];
[sp setTitle:@"Save Content of Quartz Device to PDF file"];
[sp setTitle:NLS(@"Save Content of Quartz Device to PDF file")];
answer = [sp runModal];
if(answer == NSOKButton) {
/* The following code should create a PDF file form the draw: method of deviceView
Expand Down
22 changes: 11 additions & 11 deletions R.xcode/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1054,71 +1054,71 @@
sourceTree = "<group>";
};
16A25F64072AAD110047E009 = {
fileEncoding = 30;
fileEncoding = 4;
isa = PBXFileReference;
lastKnownFileType = sourcecode.c.h;
path = AMPreferencePane.h;
refType = 4;
sourceTree = "<group>";
};
16A25F65072AAD110047E009 = {
fileEncoding = 30;
fileEncoding = 4;
isa = PBXFileReference;
lastKnownFileType = sourcecode.c.objc;
path = AMPreferencePane.m;
refType = 4;
sourceTree = "<group>";
};
16A25F66072AAD110047E009 = {
fileEncoding = 30;
fileEncoding = 4;
isa = PBXFileReference;
lastKnownFileType = sourcecode.c.h;
path = AMPreferenceWindowController.h;
refType = 4;
sourceTree = "<group>";
};
16A25F67072AAD110047E009 = {
fileEncoding = 30;
fileEncoding = 4;
isa = PBXFileReference;
lastKnownFileType = sourcecode.c.objc;
path = AMPreferenceWindowController.m;
refType = 4;
sourceTree = "<group>";
};
16A25F68072AAD110047E009 = {
fileEncoding = 30;
fileEncoding = 4;
isa = PBXFileReference;
lastKnownFileType = sourcecode.c.h;
path = AMPrefPaneIcon.h;
refType = 4;
sourceTree = "<group>";
};
16A25F69072AAD110047E009 = {
fileEncoding = 30;
fileEncoding = 4;
isa = PBXFileReference;
lastKnownFileType = sourcecode.c.objc;
path = AMPrefPaneIcon.m;
refType = 4;
sourceTree = "<group>";
};
16A25F6A072AAD110047E009 = {
fileEncoding = 30;
fileEncoding = 4;
isa = PBXFileReference;
lastKnownFileType = sourcecode.c.h;
path = AMPrefPaneIconView.h;
refType = 4;
sourceTree = "<group>";
};
16A25F6B072AAD110047E009 = {
fileEncoding = 30;
fileEncoding = 4;
isa = PBXFileReference;
lastKnownFileType = sourcecode.c.objc;
path = AMPrefPaneIconView.m;
refType = 4;
sourceTree = "<group>";
};
16A25F6C072AAD110047E009 = {
fileEncoding = 30;
fileEncoding = 4;
isa = PBXFileReference;
lastKnownFileType = sourcecode.c.h;
path = AMPrefPaneProtocol.h;
Expand All @@ -1142,15 +1142,15 @@
sourceTree = "<group>";
};
16A25F6F072AAD120047E009 = {
fileEncoding = 30;
fileEncoding = 4;
isa = PBXFileReference;
lastKnownFileType = sourcecode.c.h;
path = NSImage_AMAdditions.h;
refType = 4;
sourceTree = "<group>";
};
16A25F70072AAD120047E009 = {
fileEncoding = 30;
fileEncoding = 4;
isa = PBXFileReference;
lastKnownFileType = sourcecode.c.objc;
path = NSImage_AMAdditions.m;
Expand Down
19 changes: 17 additions & 2 deletions RController.m
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,23 @@ - (void) awakeFromNib {
// we enforce UTF-8 locale for R 2.1.0 and higher if LANG is not UTF-8 already
{
char *cloc = getenv("LANG");
if (!cloc || strlen(cloc)<7 || strcasecmp(cloc+strlen(cloc)-5,"UTF-8"))
setenv("LANG", "en_US.UTF-8", 1);
if (!cloc || strlen(cloc)<7 || strcasecmp(cloc+strlen(cloc)-5,"UTF-8")) {
/* if not set, try to figure out the locale from 'preferredLocalizations' */
char lbuf[64];
NSArray *pl = [[NSBundle mainBundle] preferredLocalizations];
strcpy(lbuf, "en_US.UTF-8");
if (pl && [pl count]>0) {
NSString *ls = (NSString*) [pl objectAtIndex:0];
if (ls && [ls length]>0 && ![ls isEqualToString:@"English"]) {
strncpy(lbuf, [ls UTF8String],48);
lbuf[48]=0;
/* FIXME: for some reason R doesn't like en.UTF-8 - as we have no region info (only 10.4+ has that) R needs en_.UTF-8 */
strcat(lbuf,"_.UTF-8");
}
}
setenv("LANG", lbuf, 1);
}
NSLog(@"Using locale \"%s\"", getenv("LANG"));
}
#endif

Expand Down
41 changes: 35 additions & 6 deletions ReadMe.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,26 @@ stefano
Milan and Augsburg, 2004-10-10

=== Note to developers ===

If you intend to work on the source code of R.app, please adjust your editor to use tabs. Each indentation level
should be exactly one tab. The preferred setting in Xcode is (in Preferences -> TextEditing)
[X] Editor uses tabs
Tab width: [4] Indent width: [4]

This will give you the proper indenting behavior and fairly well readable code. You can replace the "4" in both fields by
any positive value you find pleasant, just make sure both entries are identical. Use Xcode-style indentation whenever possible.
The strict use of tabs as indentation marks makes it possible for everyone to view the code with the spacing s/he prefers.

Update (2005-01-13, SU) About localization:
We have added new (experimental) support for localization of the GUI. Although this is great news for the users, this requires good cooperation of the developer and some extra work. If you add and language-dependent constants (like @"Choose a file"), first look up in Localized.strings whether there is such text alrady and if so use it 1:1 in the NLS(...) macro. If there is no such entry, add it to the corresponding localized files and flag those additions by an empty comment (e.g. @"Save"=@"Save"; // ), such that it can be localized later by our translators.
If you make any changes to the NIB files, always remember to update the locallized versions. You can use "nibtool" to perform the updates semi-automatically. It is ok to wait with the update if you have more batch updates, because the changes can be made incrementally.
About Localization - Quick Overview
-------------------------------------
We have added new (experimental) support for localization of the GUI. Although this is great news for the users, this requires cooperation of the developer and some extra work. Please read "Localizing Obj-C code" amd "NIB localization" below!

Update (2005-02-01, SU)
There is a script "update.localization" in the project directory that automatically updates localized NIBs to match changes made in the master 'English' versions. It is the aggressive form of NIB update (see nibtool) which means that it retains only sizes of existing components, but any other changes made to the localized NIB after translation will be lost. It also generates corresponding <nib>.<lang>.strings files that can be used for translation. Any existing files (localized NIBs and NIB-relased string files) will be overwritten.

Analogously there is a script "update.strings" for automatic merging of newly added Obj-C strings. Again, read next sections for details.

** I can't stress this often enough - make sure your editor is set to UTF-8 encoding when editing localization-related files! Even the default in Xcode is MacRoman, so make sure you set it to UTF-8 in your preferences! If you don't, then Xcode will open UTF-8 files as MacRoman thus ruining the file! All localization tools described here handle UTF-8 ONLY! **

How To - NIB localization:
----------------------------
* adding new localization
Expand All @@ -68,12 +73,36 @@ There is a script "update.localization" in the project directory that automatica
this synchronizes the changes made in the master with other locales. This also generates a new set of Translated.strings files

[the following is optional]
- edit the translation file. This is necessary if new widgets have been added and thus they need to be translated.
- edit the translation file. This is necessary if new widgets have been added and thus they need to be translated. Again, make sure you use UTF-8 encoding!
- run update.localization -t
again, don't forget the -t option or your new translation file will be overwritten

Some notes about NIB files:
Some notes on NIB files:
- It is a good idea to check the translation files even if you actually don't want to translate the NIB. The file will show you any inconsistencies in the strings used, such as trailing spaces or newlines.
- When desigining a view, always keep in mind that many languages need more space for the same phrase than english. Keep sufficient space around/following a text such that the localized files don't need to be modified one by one. (I could probably remove this one if we used German as the master language ;)).
- Don't forget to re-run update.localization when you make non-GUI changes to the NIBs, such as new connections. It's easy to forget, because it has nothing to do with the GUI, but still, the localized NIBs need to be updated, too.
- Always run update.localization before a release

Localizing Obj-C code
-----------------------

When writing code, keep in mind that all user-visible string constants should be localized. The Apple-documented way is to use NSLocalizedString macros (see Cocoa deocumentation), but to make it somewhat easier, there are NLS and NLSC macros in RGUI.h which should be used INSTEAD! They are equivalent to NSLocalizableString(xx,xx) with NLS passing an empty string as comment. The reason for the macros (beside reducing the typing effort) is that there are also some scripts that allow us to automate and simplify the process. Both macros can be used with Obj-C strings ONLY. Handling of C strings is not supported yet (use NSString whenever you can!).

Macros:
NLS(@"text")
NLSC(@"text", @"comment to clarify the context - not visible to user, only visible to the translator")
Examples:
NSString *message = NLS(@"Hello, world");
[item setValue: [NSString stringWithFormat: NLS(@"Hello, %@"), name]];
[toolbar setLabel: NLSC(@"Add Col", @"Add column - toolbar entry, keep short!")];

The most straight-forward way to localize existing code is to replace any (user-visible) @".." string constant with NLS(@".."). Note that NSLog messages and fixed strings (e.g. keys used in preferences) should not be translated.

Once the code is ready, run (in project directory)
./update.strings
this script generates Localized.strings from the sources and merges localization from each language into a new file, replacing old localization. It relies on two other scripts: 'filterNLS' which filters all NLS/NLSC macros and generates Localized.strings (using genstrings and iconv) and 'mergeLS' which merges changes into a localized version of the strings. In addition, empty comments (i.e. all NLS entries) are replaced by @"From: <file> (<function>)" to provide some context. Warnings of multiple key use can be safely ignored if the meaning is consistent.

Some practical notes:
- If you CHANGE the handle in the Obj-C code, the previous localization is lost. You should NEVER change the handle, unless you have really strong reason to do so. Note that changing the english text can be done through Localizable.strings, too! You don't have to change the handle to rephrase a given text.
- It is OK to change the comment part when using NLSC, because that information is not used for merging.
- One handle can have one translation only. If you need the same text in two different contexts, use different handles and change the english text in the localization file.
Loading

0 comments on commit 107c81f

Please sign in to comment.