mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-29 16:01:38 +00:00
New tool
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@13525 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
c833799b37
commit
6d76b5b2b7
15 changed files with 1934 additions and 2 deletions
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,11 @@
|
|||
2002-04-22 Adam Fedor <fedor@gnu.org>
|
||||
|
||||
* Tools/make_strings: New tool from Alexander Malmberg
|
||||
<alexander@malmberg.org>
|
||||
|
||||
* Source/Additional/Makefile.preamble (ADDITIONAL_OBJCFLAGS):
|
||||
Add for building DLL on mingw32
|
||||
|
||||
2002-04-20 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/NSURL.m: ([-absoluteString]) anonymous bugfix applied.
|
||||
|
@ -28,7 +36,7 @@
|
|||
|
||||
* Documentation/coding-standards.texi: Remove info dir tag.
|
||||
* Documentation/gnustep-base.texi: Idem.
|
||||
* Resources/Languages/Slovak: New file.
|
||||
* Resources/Languages/Slovak: New file (from Stefan Urbanek).
|
||||
|
||||
Thu Apr 18 11:10:04 2002 Nicola Pero <n.pero@mi.flashnet.it>
|
||||
|
||||
|
|
|
@ -42,7 +42,11 @@
|
|||
ADDITIONAL_CPPFLAGS = $(DEFS) $(CONFIG_SYSTEM_DEFS) -Wall
|
||||
|
||||
# Additional flags to pass to the Objective-C compiler
|
||||
ADDITIONAL_OBJCFLAGS =
|
||||
#ADDITIONAL_OBJCFLAGS =
|
||||
|
||||
ifeq ($(GNUSTEP_TARGET_OS),mingw32)
|
||||
ADDITIONAL_OBJCFLAGS += -DBUILD_libgnustep_base_DLL=1
|
||||
endif
|
||||
|
||||
# Additional flags to pass to the C compiler
|
||||
ADDITIONAL_CFLAGS =
|
||||
|
|
|
@ -46,6 +46,8 @@ CTOOL_NAME = gdomap
|
|||
|
||||
TEST_TOOL_NAME = locale_alias
|
||||
|
||||
SUBPROJECTS = make_strings
|
||||
|
||||
# The source files to be compiled
|
||||
autogsdoc_OBJC_FILES = autogsdoc.m AGSParser.m AGSOutput.m AGSIndex.m AGSHtml.m
|
||||
cvtenc_OBJC_FILES = cvtenc.m
|
||||
|
@ -91,6 +93,7 @@ include Makefile.preamble
|
|||
|
||||
include $(GNUSTEP_MAKEFILES)/tool.make
|
||||
include $(GNUSTEP_MAKEFILES)/ctool.make
|
||||
include $(GNUSTEP_MAKEFILES)/aggregate.make
|
||||
|
||||
ifeq ($(doc),yes)
|
||||
include $(GNUSTEP_MAKEFILES)/documentation.make
|
||||
|
|
38
Tools/make_strings/GNUmakefile
Normal file
38
Tools/make_strings/GNUmakefile
Normal file
|
@ -0,0 +1,38 @@
|
|||
#
|
||||
# make_strings makefile for GNUstep Base Library
|
||||
# Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
#
|
||||
# Written by: Adam Fedor <fedor@gnu.org>
|
||||
#
|
||||
# This file is part of the GNUstep Base Library.
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Library General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Library General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Library General Public
|
||||
# License along with this library; if not, write to the Free
|
||||
# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
# Install into the system root by default
|
||||
|
||||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
|
||||
VERSION = 0.4.2
|
||||
PACKAGE_NAME = make_strings
|
||||
TOOL_NAME = make_strings
|
||||
|
||||
make_strings_OBJC_FILES = \
|
||||
make_strings.m \
|
||||
SourceEntry.m \
|
||||
StringsEntry.m \
|
||||
StringsFile.m
|
||||
|
||||
include $(GNUSTEP_MAKEFILES)/tool.make
|
||||
|
31
Tools/make_strings/README
Normal file
31
Tools/make_strings/README
Normal file
|
@ -0,0 +1,31 @@
|
|||
make_strings
|
||||
============
|
||||
copyright 2002 Alexander Malmberg <alexander@malmberg.org>
|
||||
|
||||
If you are a translator, you're probably looking for Using.txt .
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
make_strings parses Objective-C files and builds lists of localizable
|
||||
strings. It then creates new .strings files or merges the strings with
|
||||
existing .strings files. It's fairly intelligent when matching old
|
||||
and new strings, and produces .strings files that are (supposed to be)
|
||||
easy for a translator to work with.
|
||||
|
||||
Instructions on how to use it when translating can be found in Using.txt .
|
||||
|
||||
|
||||
Installing
|
||||
----------
|
||||
|
||||
make_strings requires gnustep-make and gnustep-base.
|
||||
|
||||
Running:
|
||||
make
|
||||
|
||||
should compile, and:
|
||||
make install
|
||||
|
||||
should install it.
|
||||
|
42
Tools/make_strings/SourceEntry.h
Normal file
42
Tools/make_strings/SourceEntry.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/* SourceEntry
|
||||
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Alexander Malmberg <alexander@malmberg.org>
|
||||
Created: 2002
|
||||
|
||||
This file is part of the GNUstep Project
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef SourceEntry_h
|
||||
#define SourceEntry_h
|
||||
|
||||
@interface SourceEntry : NSObject
|
||||
{
|
||||
NSString *file,*comment,*key;
|
||||
unsigned int line;
|
||||
}
|
||||
|
||||
/* TODO: very cryptic error message if duplicate name in argument list,
|
||||
gcc issue */
|
||||
- initWithKey: (NSString *)k comment: (NSString *)c file: (NSString *)f line: (unsigned int)l;
|
||||
|
||||
-(NSString *) file;
|
||||
-(NSString *) comment;
|
||||
-(NSString *) key;
|
||||
-(unsigned int) line;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
63
Tools/make_strings/SourceEntry.m
Normal file
63
Tools/make_strings/SourceEntry.m
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* SourceEntry
|
||||
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Alexander Malmberg <alexander@malmberg.org>
|
||||
Created: 2002
|
||||
|
||||
This file is part of the GNUstep Project
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <Foundation/NSObject.h>
|
||||
#include <Foundation/NSString.h>
|
||||
|
||||
#include "SourceEntry.h"
|
||||
|
||||
@implementation SourceEntry
|
||||
|
||||
- initWithKey: (NSString *)k comment: (NSString *)c file: (NSString *)f
|
||||
line: (unsigned int)l
|
||||
{
|
||||
self=[super init];
|
||||
|
||||
ASSIGN(file,f);
|
||||
ASSIGN(comment,c);
|
||||
ASSIGN(key,k);
|
||||
line=l;
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void) dealloc
|
||||
{
|
||||
DESTROY(file);
|
||||
DESTROY(comment);
|
||||
DESTROY(key);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
-(NSString *) description
|
||||
{
|
||||
return [NSString
|
||||
stringWithFormat: @"(key='%@' comment='%@' at '%@':%i)",
|
||||
key,comment,file,line];
|
||||
}
|
||||
|
||||
|
||||
-(NSString *) file { return file; }
|
||||
-(NSString *) comment { return comment; }
|
||||
-(NSString *) key { return key; }
|
||||
-(unsigned int) line { return line; }
|
||||
|
||||
@end
|
||||
|
72
Tools/make_strings/StringsEntry.h
Normal file
72
Tools/make_strings/StringsEntry.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/* StringsEntry
|
||||
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Alexander Malmberg <alexander@malmberg.org>
|
||||
Created: 2002
|
||||
|
||||
This file is part of the GNUstep Project
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef StringsEntry_h
|
||||
#define StringsEntry_h
|
||||
|
||||
@class SourceEntry;
|
||||
|
||||
@interface StringsEntry : NSObject
|
||||
{
|
||||
NSString *key,*comment,*translated;
|
||||
NSString *user_comment;
|
||||
|
||||
#define FLAG_UNTRANSLATED 0x01
|
||||
#define FLAG_UNMATCHED 0x02
|
||||
int flags;
|
||||
|
||||
NSString *file;
|
||||
unsigned int line;
|
||||
}
|
||||
|
||||
+ stringsEntryFromSourceEntry: (SourceEntry *)se;
|
||||
|
||||
- initWithKey: (NSString *)k comment: (NSString *)c translated: (NSString *)t userComment: (NSString *)uc
|
||||
flags: (int)flags file: (NSString *)filename line: (int)line;
|
||||
|
||||
-(NSString *) key;
|
||||
-(NSString *) comment;
|
||||
-(NSString *) translated;
|
||||
-(NSString *) userComment;
|
||||
|
||||
-(int) flags;
|
||||
|
||||
-(NSString *) file;
|
||||
-(unsigned int) line;
|
||||
|
||||
-(int) compareFileLine: (StringsEntry *)e;
|
||||
-(int) compareFileKeyComment: (StringsEntry *)e;
|
||||
|
||||
|
||||
-(void) setKey: (NSString *)k;
|
||||
-(void) setComment: (NSString *)c;
|
||||
-(void) setTranslated: (NSString *)t;
|
||||
-(void) setUserComment: (NSString *)uc;
|
||||
|
||||
-(void) setFlags: (int)f;
|
||||
-(void) addFlag: (int)f;
|
||||
|
||||
-(void) setFile: (NSString *)f;
|
||||
-(void) setLine: (unsigned int)l;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
121
Tools/make_strings/StringsEntry.m
Normal file
121
Tools/make_strings/StringsEntry.m
Normal file
|
@ -0,0 +1,121 @@
|
|||
/* StringsEntry
|
||||
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Alexander Malmberg <alexander@malmberg.org>
|
||||
Created: 2002
|
||||
|
||||
This file is part of the GNUstep Project
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <Foundation/NSObject.h>
|
||||
#include <Foundation/NSArray.h>
|
||||
|
||||
#include "StringsEntry.h"
|
||||
|
||||
#include "SourceEntry.h"
|
||||
|
||||
|
||||
@implementation StringsEntry
|
||||
|
||||
+ stringsEntryFromSourceEntry: (SourceEntry *)e
|
||||
{
|
||||
return AUTORELEASE([[self alloc] initWithKey: [e key] comment: [e comment] translated: [e key] userComment: nil
|
||||
flags: FLAG_UNTRANSLATED file: [e file] line: [e line]]);
|
||||
}
|
||||
|
||||
|
||||
- initWithKey: (NSString *)k comment: (NSString *)c translated: (NSString *)t userComment: (NSString *)uc
|
||||
flags: (int)f file: (NSString *)filename line: (int)l
|
||||
{
|
||||
self=[super init];
|
||||
ASSIGN(key,k);
|
||||
ASSIGN(comment,c);
|
||||
ASSIGN(translated,t);
|
||||
ASSIGN(user_comment,uc);
|
||||
flags=f;
|
||||
ASSIGN(file,filename);
|
||||
line=l;
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void) dealloc
|
||||
{
|
||||
DESTROY(key);
|
||||
DESTROY(comment);
|
||||
DESTROY(translated);
|
||||
DESTROY(user_comment);
|
||||
DESTROY(file);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
-(NSString *) key { return key; }
|
||||
-(NSString *) comment { return comment; }
|
||||
-(NSString *) translated { return translated; }
|
||||
-(NSString *) userComment { return user_comment; }
|
||||
|
||||
-(int) flags { return flags; }
|
||||
|
||||
-(NSString *) file { return file; }
|
||||
-(unsigned int) line { return line; }
|
||||
|
||||
|
||||
-(int) compareFileLine: (StringsEntry *)e
|
||||
{
|
||||
int res=[[self file] compare: [e file]];
|
||||
if (res!=NSOrderedSame) return res;
|
||||
if ([self line]<[e line])
|
||||
return NSOrderedAscending;
|
||||
else
|
||||
return NSOrderedDescending;
|
||||
}
|
||||
|
||||
-(int) compareFileKeyComment: (StringsEntry *)e
|
||||
{
|
||||
int res;
|
||||
|
||||
res=[[self file] compare: [e file]];
|
||||
if (res!=NSOrderedSame) return res;
|
||||
|
||||
res=[[self key] compare: [e key]];
|
||||
if (res!=NSOrderedSame) return res;
|
||||
|
||||
if (![self comment])
|
||||
return NSOrderedAscending;
|
||||
if (![e comment])
|
||||
return NSOrderedDescending;
|
||||
return [[self comment] compare: [e comment]];
|
||||
}
|
||||
|
||||
|
||||
-(void) setKey: (NSString *)k { ASSIGN(key,k); }
|
||||
-(void) setComment: (NSString *)c { ASSIGN(comment,c); }
|
||||
-(void) setTranslated: (NSString *)t { ASSIGN(translated,t); }
|
||||
-(void) setUserComment: (NSString *)uc { ASSIGN(user_comment,uc); }
|
||||
|
||||
-(void) setFlags: (int)f { flags=f; }
|
||||
-(void) addFlag: (int)f { flags|=f; }
|
||||
|
||||
-(void) setFile: (NSString *)f { ASSIGN(file,f); }
|
||||
-(void) setLine: (unsigned int)l { line=l; }
|
||||
|
||||
|
||||
-(NSString *) description
|
||||
{
|
||||
return [NSString
|
||||
stringWithFormat: @"(key='%@' comment='%@' at '%@':%i userComment='%@' translated='%@' flags=%02x)",
|
||||
key,comment,file,line,user_comment,translated,flags];
|
||||
}
|
||||
|
||||
@end
|
||||
|
44
Tools/make_strings/StringsFile.h
Normal file
44
Tools/make_strings/StringsFile.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* StringsFile
|
||||
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Alexander Malmberg <alexander@malmberg.org>
|
||||
Created: 2002
|
||||
|
||||
This file is part of the GNUstep Project
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef StringsFile_h
|
||||
#define StringsFile_h
|
||||
|
||||
@class StringsEntry;
|
||||
@class SourceEntry;
|
||||
@class NSMutableArray;
|
||||
|
||||
@interface StringsFile : NSObject
|
||||
{
|
||||
NSMutableArray *strings;
|
||||
NSString *global_comment;
|
||||
}
|
||||
|
||||
- init;
|
||||
- initWithFile: (NSString *)filename;
|
||||
|
||||
-(BOOL) writeToFile: (NSString *)filename;
|
||||
|
||||
-(void) addSourceEntry: (SourceEntry *)e;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
553
Tools/make_strings/StringsFile.m
Normal file
553
Tools/make_strings/StringsFile.m
Normal file
|
@ -0,0 +1,553 @@
|
|||
/* StringsFile
|
||||
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Alexander Malmberg <alexander@malmberg.org>
|
||||
Created: 2002
|
||||
|
||||
This file is part of the GNUstep Project
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <Foundation/NSObject.h>
|
||||
#include <Foundation/NSString.h>
|
||||
#include <Foundation/NSArray.h>
|
||||
#include <Foundation/NSFileManager.h>
|
||||
#include <Foundation/NSDate.h>
|
||||
|
||||
#include "StringsFile.h"
|
||||
|
||||
#include "StringsEntry.h"
|
||||
#include "SourceEntry.h"
|
||||
|
||||
#include "make_strings.h"
|
||||
|
||||
|
||||
static NSString *parse_string(NSString **ptr)
|
||||
{
|
||||
NSString *str=*ptr;
|
||||
NSString *ret;
|
||||
int i,c;
|
||||
unichar ch;
|
||||
|
||||
c=[str length];
|
||||
for (i=0;i<c;i++)
|
||||
{
|
||||
ch=[str characterAtIndex: i];
|
||||
if (ch=='\\')
|
||||
{
|
||||
if (i==c)
|
||||
{
|
||||
fprintf(stderr,"parse error, \\ without second character\n");
|
||||
exit(1);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (ch=='\"')
|
||||
break;
|
||||
}
|
||||
if (i==c)
|
||||
{
|
||||
fprintf(stderr,"parse error, unterminated string\n");
|
||||
exit(1);
|
||||
}
|
||||
ret=[str substringToIndex: i];
|
||||
str=[str substringFromIndex: i+1];
|
||||
*ptr=str;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#define DUMMY @"<dummy>"
|
||||
#define DUMMY2 @"<dummy2>"
|
||||
|
||||
@implementation StringsFile
|
||||
|
||||
- init
|
||||
{
|
||||
self=[super init];
|
||||
strings=[[NSMutableArray alloc] init];
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void) dealloc
|
||||
{
|
||||
DESTROY(global_comment);
|
||||
DESTROY(strings);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- initWithFile: (NSString *)filename
|
||||
{
|
||||
NSString *str;
|
||||
|
||||
self=[self init];
|
||||
|
||||
str=[NSString stringWithContentsOfFile: filename];
|
||||
if (!str) return self;
|
||||
|
||||
{
|
||||
StringsEntry *se=nil;
|
||||
NSMutableArray *update_list=[[NSMutableArray alloc] init];
|
||||
NSArray *lines;
|
||||
NSString *l;
|
||||
int i,c,pos;
|
||||
NSMutableDictionary *dummy_entries=[[NSMutableDictionary alloc] init];
|
||||
|
||||
NSMutableString *user_comment=[[NSMutableString alloc] init];
|
||||
|
||||
NSString *key,*trans;
|
||||
|
||||
/* this is a bit yucky, but it works */
|
||||
lines=[str componentsSeparatedByString: @"/*"];
|
||||
c=[lines count];
|
||||
for (i=0;i<c;i++)
|
||||
{
|
||||
l=[lines objectAtIndex: i];
|
||||
/* First entry has everything before the first comment and needs
|
||||
to be handled specially. */
|
||||
if (i)
|
||||
{
|
||||
/* Parse special comments. */
|
||||
if ([l hasPrefix: @"**"])
|
||||
{ /* It's one of our banners, just ignore it. If it's the first
|
||||
one we put all comments so far in the global user comment. */
|
||||
if (user_comment)
|
||||
{
|
||||
if (![user_comment isEqual: @""])
|
||||
global_comment=[user_comment copy];
|
||||
DESTROY(user_comment);
|
||||
}
|
||||
}
|
||||
else if ([l hasPrefix: @" File: "])
|
||||
{
|
||||
se=[[StringsEntry alloc] init];
|
||||
[se addFlag: FLAG_UNMATCHED];
|
||||
[update_list addObject: se];
|
||||
[se release];
|
||||
|
||||
l=[l substringFromIndex: 7];
|
||||
pos=[l rangeOfString: @":"].location;
|
||||
[se setFile: [l substringToIndex: pos]];
|
||||
l=[l substringFromIndex: pos+1];
|
||||
[se setLine: [l intValue]];
|
||||
}
|
||||
else if ([l hasPrefix: @" Flag: untranslated */"])
|
||||
[se addFlag: FLAG_UNTRANSLATED];
|
||||
else if ([l hasPrefix: @" Flag: unmatched */"])
|
||||
[se addFlag: FLAG_UNMATCHED]; /* this is essentially a noop */
|
||||
else if ([l hasPrefix: @" Comment: "])
|
||||
{
|
||||
l=[l substringFromIndex: 10];
|
||||
pos=[l rangeOfString: @" */"].location;
|
||||
[se setComment: [l substringToIndex: pos]];
|
||||
}
|
||||
else
|
||||
{
|
||||
pos=[l rangeOfString: @"*/"].location;
|
||||
if ([user_comment length])
|
||||
[user_comment appendString: @"\n"];
|
||||
[user_comment appendString: [l substringToIndex: pos]];
|
||||
}
|
||||
|
||||
pos=[l rangeOfString: @"*/"].location;
|
||||
if (pos==NSNotFound) continue;
|
||||
l=[l substringFromIndex: pos+2];
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
pos=[l rangeOfString: @"\""].location;
|
||||
if (pos==NSNotFound) break;
|
||||
|
||||
l=[l substringFromIndex: pos+1];
|
||||
key=parse_string(&l);
|
||||
|
||||
pos=[l rangeOfString: @"="].location;
|
||||
if (pos==NSNotFound)
|
||||
{
|
||||
fprintf(stderr,"parse error in '%s', expecting '='\n",[filename cString]);
|
||||
exit(1);
|
||||
}
|
||||
l=[l substringFromIndex: pos+1];
|
||||
pos=[l rangeOfString: @"\""].location;
|
||||
if (pos==NSNotFound)
|
||||
{
|
||||
fprintf(stderr,"parse error in '%s', expecting second string\n",[filename cString]);
|
||||
exit(1);
|
||||
}
|
||||
l=[l substringFromIndex: pos+1];
|
||||
trans=parse_string(&l);
|
||||
|
||||
pos=[l rangeOfString: @";"].location;
|
||||
if (pos==NSNotFound)
|
||||
{
|
||||
fprintf(stderr,"parse error in '%s', expecting ';'\n",[filename cString]);
|
||||
exit(1);
|
||||
}
|
||||
l=[l substringFromIndex: pos+1];
|
||||
|
||||
if (![update_list count])
|
||||
{ /* we're probably parsing a file not created by us */
|
||||
if (![dummy_entries objectForKey: key])
|
||||
{
|
||||
se=[[StringsEntry alloc] init];
|
||||
[se setFile: DUMMY];
|
||||
[se setFlags: FLAG_UNMATCHED];
|
||||
[update_list addObject: se];
|
||||
[se release];
|
||||
[dummy_entries setObject: se forKey: key];
|
||||
}
|
||||
}
|
||||
|
||||
[update_list makeObjectsPerformSelector: @selector(setKey:) withObject: key];
|
||||
[update_list makeObjectsPerformSelector: @selector(setTranslated:) withObject: trans];
|
||||
/* {
|
||||
int i,c=[update_list count];
|
||||
for (i=0;i<c;i++)
|
||||
{
|
||||
printf("%4i : %@\n",i,[update_list objectAtIndex: i]);
|
||||
}
|
||||
}*/
|
||||
|
||||
[strings addObjectsFromArray: update_list];
|
||||
|
||||
[update_list removeAllObjects];
|
||||
se=nil;
|
||||
}
|
||||
}
|
||||
|
||||
DESTROY(user_comment);
|
||||
DESTROY(dummy_entries);
|
||||
DESTROY(update_list);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
-(void) _writeTo: (NSMutableString *)str entryHead: (StringsEntry *)se
|
||||
{
|
||||
if ([se file])
|
||||
{
|
||||
[str appendString: @"/* File: "];
|
||||
[str appendString: [se file]];
|
||||
[str appendString: [NSString stringWithFormat: @":%i */\n",[se line]]];
|
||||
}
|
||||
if ([se comment])
|
||||
{
|
||||
[str appendString: @"/* Comment: "];
|
||||
[str appendString: [se comment]];
|
||||
[str appendString: @" */\n"];
|
||||
}
|
||||
}
|
||||
|
||||
-(void) _writeTo: (NSMutableString *)str entryFlags: (StringsEntry *)se
|
||||
{
|
||||
int flags=[se flags];
|
||||
if (!flags) return;
|
||||
if (flags&FLAG_UNMATCHED)
|
||||
[str appendString: @"/* Flag: unmatched */\n"];
|
||||
else
|
||||
if (flags&FLAG_UNTRANSLATED)
|
||||
[str appendString: @"/* Flag: untranslated */\n"];
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"unknown flag %08x\n",flags);
|
||||
}
|
||||
}
|
||||
|
||||
-(void) _writeTo: (NSMutableString *)str entryKey: (StringsEntry *)se
|
||||
{
|
||||
[str appendString: @"\""];
|
||||
[str appendString: [se key]];
|
||||
|
||||
if ([[se key] length]+[[se translated] length]<70)
|
||||
[str appendString: @"\" = \""];
|
||||
else
|
||||
[str appendString: @"\"\n= \""];
|
||||
|
||||
[str appendString: [se translated]];
|
||||
[str appendString: @"\";\n"];
|
||||
}
|
||||
|
||||
|
||||
-(void) _writeTo: (NSMutableString *)str manyEntries: (NSMutableArray *)list
|
||||
{
|
||||
int i,c;
|
||||
StringsEntry *tr,*cur;
|
||||
|
||||
[list sortUsingSelector: @selector(compareFileLine:)];
|
||||
c=[list count];
|
||||
if (!c) return;
|
||||
cur=tr=nil;
|
||||
for (i=0;i<c;i++)
|
||||
{
|
||||
cur=[list objectAtIndex: i];
|
||||
[self _writeTo: str entryHead: cur];
|
||||
if ([cur flags])
|
||||
[self _writeTo: str entryFlags: cur];
|
||||
|
||||
if (!([cur flags]&FLAG_UNTRANSLATED))
|
||||
tr=cur;
|
||||
}
|
||||
if (tr)
|
||||
[self _writeTo: str entryKey: tr];
|
||||
else
|
||||
[self _writeTo: str entryKey: cur];
|
||||
}
|
||||
|
||||
|
||||
-(BOOL) writeToFile: (NSString *)filename
|
||||
{
|
||||
int i,c;
|
||||
BOOL result;
|
||||
NSMutableString *str=[[NSMutableString alloc] initWithCapacity: 32*1024];
|
||||
StringsEntry *se;
|
||||
|
||||
NSMutableArray *strings_left=[strings mutableCopy];
|
||||
NSMutableArray *str_list=[[NSMutableArray alloc] init];
|
||||
NSMutableArray *dup_list=[[NSMutableArray alloc] init];
|
||||
NSMutableArray *un_list=[[NSMutableArray alloc] init];
|
||||
|
||||
StringsEntry *cur,*c2;
|
||||
|
||||
int single_file,wrote_banner,unflags;
|
||||
int un_count=0;
|
||||
|
||||
if (global_comment && ![global_comment isEqual: @""])
|
||||
{
|
||||
[str appendString: @"/*"];
|
||||
[str appendString: global_comment];
|
||||
[str appendString: @"*/\n\n"];
|
||||
}
|
||||
|
||||
[str appendString:
|
||||
[NSString stringWithFormat:
|
||||
@"/***\n"
|
||||
@"%@\n"
|
||||
@"updated by make_strings %@\n"
|
||||
@"add comments above this one\n"
|
||||
@"***/\n",
|
||||
filename,[NSDate dateWithTimeIntervalSinceNow: 0]]];
|
||||
|
||||
wrote_banner=0;
|
||||
|
||||
/* First, output all keys that appear in multiple places (unless all
|
||||
appearances are in one file and none are marked unmatched or untranslated).
|
||||
Collect unmatched or untranslated single entries in un_list and matched
|
||||
translated (single/multiple in one file) entries in str_list. */
|
||||
while ([strings_left count])
|
||||
{
|
||||
cur=[strings_left objectAtIndex: 0];
|
||||
if (([cur flags]&(FLAG_UNMATCHED|FLAG_UNTRANSLATED))==
|
||||
(FLAG_UNMATCHED|FLAG_UNTRANSLATED)
|
||||
|| (aggressive_import && [[cur file] isEqual: DUMMY2]))
|
||||
{ /* ignore strings that are unmatched _and_ untranslated */
|
||||
[strings_left removeObjectAtIndex: 0];
|
||||
continue;
|
||||
}
|
||||
[dup_list addObject: cur];
|
||||
[strings_left removeObjectAtIndex: 0];
|
||||
|
||||
single_file=1;
|
||||
unflags=[cur flags];
|
||||
for (i=0;i<[strings_left count];i++)
|
||||
{
|
||||
c2=[strings_left objectAtIndex: i];
|
||||
|
||||
if (([c2 flags]&(FLAG_UNMATCHED|FLAG_UNTRANSLATED))==
|
||||
(FLAG_UNMATCHED|FLAG_UNTRANSLATED)
|
||||
|| (aggressive_import && [[cur file] isEqual: DUMMY2]))
|
||||
{ /* ignore strings that are unmatched _and_ untranslated */
|
||||
[strings_left removeObjectAtIndex: i];
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([[cur key] isEqual: [c2 key]])
|
||||
{
|
||||
unflags|=[c2 flags];
|
||||
[dup_list addObject: c2];
|
||||
[strings_left removeObjectAtIndex: i];
|
||||
if (single_file)
|
||||
if (![[cur file] isEqual: [c2 file]])
|
||||
single_file=0;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if (single_file && !unflags)
|
||||
{
|
||||
[str_list addObjectsFromArray: dup_list];
|
||||
[dup_list removeAllObjects];
|
||||
continue;
|
||||
}
|
||||
if ([dup_list count]==1)
|
||||
{
|
||||
[un_list addObjectsFromArray: dup_list];
|
||||
[dup_list removeAllObjects];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (unflags)
|
||||
un_count+=[dup_list count];
|
||||
|
||||
if (!wrote_banner)
|
||||
{
|
||||
[str appendString: @"\n\n/*** Keys found in multiple places ***/\n"];
|
||||
wrote_banner=1;
|
||||
}
|
||||
|
||||
[str appendString: @"\n"];
|
||||
[self _writeTo: str manyEntries: dup_list];
|
||||
[dup_list removeAllObjects];
|
||||
}
|
||||
|
||||
DESTROY(strings_left);
|
||||
|
||||
/* Now output all single unmatched or untranslated entries. Order by line
|
||||
and file so key changes and movements are easy to spot and fix. */
|
||||
if ([un_list count])
|
||||
{
|
||||
[str appendString: @"\n\n/*** Unmatched/untranslated keys ***/\n"];
|
||||
[un_list sortUsingSelector: @selector(compareFileLine:)];
|
||||
c=[un_list count];
|
||||
un_count+=c;
|
||||
for (i=0;i<c;i++)
|
||||
{
|
||||
se=[un_list objectAtIndex: i];
|
||||
[str appendString: @"\n"];
|
||||
[self _writeTo: str entryHead: se];
|
||||
[self _writeTo: str entryFlags: se];
|
||||
[self _writeTo: str entryKey: se];
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally, output all matched and translated entries ordered by file. The
|
||||
translator should never have to touch these strings (unless there are typos
|
||||
or something). */
|
||||
if ([str_list count])
|
||||
{
|
||||
NSString *last_filename=nil;
|
||||
|
||||
[str_list sortUsingSelector: @selector(compareFileKeyComment:)];
|
||||
c=[str_list count];
|
||||
for (i=0;i<c;i++)
|
||||
{
|
||||
se=[str_list objectAtIndex: i];
|
||||
if (!last_filename || ![last_filename isEqual: [se file]])
|
||||
{
|
||||
last_filename=[se file];
|
||||
[str appendString:
|
||||
[NSString stringWithFormat: @"\n\n/*** Strings from %@ ***/\n",
|
||||
last_filename]];
|
||||
}
|
||||
[self _writeTo: str entryHead: se];
|
||||
if (i==c-1 || ![[se key] isEqual: [[str_list objectAtIndex: i+1] key]])
|
||||
[self _writeTo: str entryKey: se];
|
||||
}
|
||||
}
|
||||
DESTROY(str_list);
|
||||
DESTROY(dup_list);
|
||||
|
||||
{
|
||||
NSString *backupname=[filename stringByAppendingString: @"~"];
|
||||
[[NSFileManager defaultManager] removeFileAtPath: backupname handler: nil];
|
||||
[[NSFileManager defaultManager] movePath: filename toPath: backupname handler: nil];
|
||||
result=[str writeToFile: filename atomically: YES];
|
||||
|
||||
if (!result)
|
||||
fprintf(stderr,"Error saving '%s'!\n",[filename cString]);
|
||||
}
|
||||
|
||||
DESTROY(str);
|
||||
DESTROY(un_list);
|
||||
|
||||
if (un_count)
|
||||
fprintf(stderr,"'%s': %i untranslated or unmatched messages\n",[filename cString],un_count);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
-(void) addSourceEntry: (SourceEntry *)e
|
||||
{
|
||||
/* First try to find a match among our unmatched strings. We consider
|
||||
two entries to match if they have the same key, file and comment. This
|
||||
could be extended, but the risk of errors increases. */
|
||||
int i,c;
|
||||
StringsEntry *se;
|
||||
|
||||
c=[strings count];
|
||||
|
||||
/* Look for exact matches. If we find an exact match (same file, key, and
|
||||
comment) we mark the StringsEntry matched and don't add the SourceEntry.
|
||||
*/
|
||||
for (i=0;i<c;i++)
|
||||
{
|
||||
se=[strings objectAtIndex: i];
|
||||
if (!([se flags]&FLAG_UNMATCHED))
|
||||
continue;
|
||||
|
||||
if (![[se key] isEqual: [e key]])
|
||||
continue;
|
||||
|
||||
if (([se flags]&FLAG_UNMATCHED) && [[se file] isEqual: [e file]])
|
||||
{
|
||||
if ((![se comment] && ![e comment]) ||
|
||||
([[se comment] isEqual: [e comment]]))
|
||||
{
|
||||
[se setFlags: [se flags]&~FLAG_UNMATCHED];
|
||||
[se setLine: [e line]];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aggressive_match)
|
||||
{
|
||||
/* If aggressive match is enabled, we try to find an existing and
|
||||
translated StringsEntry. If we find we add a new StringsEntry from
|
||||
the SourceEntry with the same translation and marked as translated.
|
||||
*/
|
||||
for (i=0;i<c;i++)
|
||||
{
|
||||
se=[strings objectAtIndex: i];
|
||||
|
||||
if ([se flags]&FLAG_UNTRANSLATED)
|
||||
continue;
|
||||
|
||||
if (![[se key] isEqual: [e key]])
|
||||
continue;
|
||||
|
||||
{
|
||||
StringsEntry *se2=[StringsEntry stringsEntryFromSourceEntry: e];
|
||||
[se2 setFlags: 0];
|
||||
[se2 setTranslated: [se translated]];
|
||||
[strings addObject: se2];
|
||||
|
||||
/* If aggressive_import is enabled and the one we matched is a
|
||||
dummy we change the name to DUMMY2 so we can ignore it later. */
|
||||
if (aggressive_import && [[se file] isEqual: DUMMY])
|
||||
[se setFile: DUMMY2];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* No match, add a new, untranslated StringsEntry. */
|
||||
[strings addObject: [StringsEntry stringsEntryFromSourceEntry: e]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
352
Tools/make_strings/Using.txt
Normal file
352
Tools/make_strings/Using.txt
Normal file
|
@ -0,0 +1,352 @@
|
|||
Translator's guide to make_strings
|
||||
==================================
|
||||
copyright 2002 Alexander Malmberg <alexander@malmberg.org>
|
||||
|
||||
This file is meant to be a fairly complete description of what a
|
||||
translator needs to do to work with make_strings. Please send comments,
|
||||
suggestions, bug reports etc. to <alexander@malmberg.org>.
|
||||
|
||||
|
||||
TODO: application developer's guide
|
||||
basically: use some function around all strings, like _() or
|
||||
NSLocalizedString() if you want a comment; don't forget to take care of
|
||||
static strings with __() or NSLocalizedStaticString().
|
||||
|
||||
|
||||
Table of contents
|
||||
-----------------
|
||||
|
||||
1. Basic stuff
|
||||
1.1. Invoking make_strings
|
||||
1.2. What make_strings parses
|
||||
|
||||
2. The .strings files
|
||||
|
||||
3. Normal tasks
|
||||
3.1. Creating the initial .strings files
|
||||
3.2. Updating the .strings files
|
||||
|
||||
4. Special cases
|
||||
4.1. Importing an existing .strings files
|
||||
|
||||
|
||||
1. Basic stuff
|
||||
==============
|
||||
|
||||
1.1. Invoking make_strings
|
||||
--------------------------
|
||||
|
||||
(In the future, running 'make strings' will (hopefully) be enough to do
|
||||
all this.)
|
||||
|
||||
The syntax for running make_strings is:
|
||||
|
||||
make_strings [--help]
|
||||
|
||||
to see some very basic help, or:
|
||||
|
||||
make_strings [--verbose] [--aggressive-import] [--aggressive-match]
|
||||
-L "Languages" file1.m file2.h ...
|
||||
|
||||
The --verbose flag makes make_strings print some information while
|
||||
running.
|
||||
|
||||
The -L flag tells make_strings which languages to process. You can have
|
||||
many -L flags, or you can specify many languages in one -L flag. You'll
|
||||
need to specify at least one language.
|
||||
|
||||
The --aggressive-match flag is described in section 3.2. It causes
|
||||
matching to be done on key only.
|
||||
|
||||
The --aggressive-import flag is described in section 4.1. It activates
|
||||
--aggressive-match and automatically removes dummy entries created
|
||||
through importing .strings files not created by make_strings.
|
||||
|
||||
All other arguments are considered filenames and are added to the list
|
||||
of files to parse for strings.
|
||||
|
||||
When make_strings is finished, it will print a message for each .strings
|
||||
file that has untranslated or unmatched strings (and thus needs to
|
||||
be updated).
|
||||
|
||||
Examples:
|
||||
|
||||
make_strings -L English -L "Swedish German" menu.m menu.h whatever.m foo.c
|
||||
|
||||
will parse the specified files and update the .strings files in
|
||||
English.lproj/, Swedish.lproj/ and German.lproj/.
|
||||
|
||||
|
||||
1.2. What make_strings parses
|
||||
-----------------------------
|
||||
make_strings has a decent parser of c-like languages. It shouldn't have
|
||||
any problems grabbing strings for a valid objective-c or c file.
|
||||
|
||||
Currently the following functions are handled:
|
||||
_(key)
|
||||
NSLocalizedString(key,comment)
|
||||
NSLocalizedStringFromTable(key,table,comment)
|
||||
NSLocalizedStringFromTableInBundle(key,table,bundle,comment)
|
||||
__(key)
|
||||
NSLocalizedStaticString(key,comment)
|
||||
|
||||
|
||||
'Clever' use of cpp can confuse make_strings, so don't do that.
|
||||
|
||||
Nested calls to localization functions aren't handled, so don't do that
|
||||
either (if you find a case where you really need to do this, explain
|
||||
why to me and I might extend it).
|
||||
|
||||
The fields make_strings uses must be string constants. Calls to
|
||||
localization functions with important parameters that aren't string
|
||||
constants will be ignored and a warning will be issued. (So note that eg.
|
||||
bundle does not have to be a string constant.)
|
||||
|
||||
|
||||
2. The .strings files
|
||||
=====================
|
||||
Each language directory contains a number of .strings files. The default
|
||||
is Localizable.strings (and most programs probably won't have any other).
|
||||
|
||||
A .strings file consists of a number of key/value pairs. The syntax is:
|
||||
|
||||
"some key" = "some value" ;
|
||||
|
||||
The key is used in the source code to lookup the translation. The value
|
||||
is the translation.
|
||||
|
||||
A .strings file can have c-style comments: /* */ . make_strings
|
||||
stores additional information in these to help it handle translations
|
||||
intelligently. Thus, you shouldn't touch the comments except as noted
|
||||
in this file. You can add a comment (or several) above the first
|
||||
make_strings banner and it will be preserved, but anything past the first
|
||||
banner will be discarded.
|
||||
|
||||
The special comments used are:
|
||||
|
||||
/* File: file.m:123 */
|
||||
|
||||
This starts a new entry (for make_strings). It tells you in which file
|
||||
and at what line the string was found.
|
||||
|
||||
/* Comment: foo bar zot */
|
||||
|
||||
The programmer can associate comments with each localizable string as
|
||||
an aid when translating.
|
||||
|
||||
/* Flag: unmatched */
|
||||
|
||||
This indicates that the string was found in the .strings file, but not
|
||||
in the source code.
|
||||
|
||||
/* Flag: untranslated */
|
||||
|
||||
This indicated that the string was found in the source code, and it
|
||||
couldn't be matched to an existing entry in the .strings file.
|
||||
|
||||
Flags and comments bind to the previous File: comment. There might be
|
||||
several File: comments for a single key/value pair. That means that the
|
||||
key appears in several places in the source code. The different File:
|
||||
comments mark the different places (and any comments or flag associated
|
||||
with that specific appearance of the key).
|
||||
|
||||
|
||||
|
||||
3.1. Normal tasks
|
||||
=================
|
||||
|
||||
3.1. Creating the initial .strings files
|
||||
----------------------------------------
|
||||
|
||||
If you want to localize an application (read application or tool) for
|
||||
the first time, or add a new language to an application, you must first
|
||||
create the .lproj directory for that language (if it doesn't already
|
||||
exist). Just run:
|
||||
|
||||
mkdir Language.lproj
|
||||
|
||||
where Language is the name of the language (eg. English). To be able
|
||||
to use the translation, you'll also need to add the language to the
|
||||
_LANGUAGES listing in GNUmakefile.
|
||||
|
||||
Example:
|
||||
SomeProgram_LANGUAGES = English Swedish German
|
||||
|
||||
You'll also need to make sure all .strings files are in
|
||||
the _LOCALIZED_RESOURCE_FILES list. Most programs use only
|
||||
Localizable.strings. If you're unsure what files to add, run make_strings
|
||||
and check what files it created.
|
||||
|
||||
Example:
|
||||
SomeProgram_LOCALIZED_RESOURCE_FILES = Localizable.strings
|
||||
|
||||
|
||||
To get the initial .strings files, simply run make_strings with the
|
||||
language as a parameter, eg.:
|
||||
|
||||
make_strings -L German *.[hm]
|
||||
|
||||
This will create any necessary .strings files in German.lproj/. Open
|
||||
each file in a text editor an proceed according to section 3.2.
|
||||
|
||||
|
||||
3.2. Updating the .strings files
|
||||
--------------------------------
|
||||
|
||||
Once you have some .strings files, you can update them anytime by running
|
||||
make_strings with the languages you want to update as arguments.
|
||||
|
||||
Example:
|
||||
make_strings -L English German Swedish *.[hm]
|
||||
|
||||
will update the .strings files in English.lproj/, German.lproj/,
|
||||
and Swedish.lproj/. If a .strings file has unmatched or untranslated
|
||||
strings, make_strings will print a message. If no messages are printed,
|
||||
the translations are up-to-date and there's nothing you need to do.
|
||||
|
||||
If a file needs to be updated, open it in your favorite text editor and
|
||||
search for 'Flag:'. Each flag marks something that needs to be taken care
|
||||
of. When you've taken care of all flags, you're done! There are two
|
||||
flags:
|
||||
|
||||
|
||||
/* Flag: untranslated */
|
||||
|
||||
This marks a string that doesn't have a (confirmed) translation yet. Enter
|
||||
the translation as the new value for and _remove_the_entire_line_ with
|
||||
the flag.
|
||||
|
||||
Example: a save menu entry was added
|
||||
|
||||
/* File: SomeWindow.m:314 */
|
||||
/* Comment: menu entry for saving a message */
|
||||
/* Flag: untranslated */
|
||||
"Save..." = "Save...";
|
||||
|
||||
Translate the string and remove the flag:
|
||||
|
||||
/* File: SomeWindow.m:314 */
|
||||
/* Comment: menu entry for saving a message */
|
||||
"Save..." = "Spara...";
|
||||
|
||||
|
||||
A message that is marked as untranslated might appear grouped with
|
||||
other strings with the same key. In that case, translating is as easy
|
||||
as verifying that the existing translation matches the new case and
|
||||
deleting the flag. (If you can't find a translation that matches all
|
||||
cases, you'll need to talk to the application's maintainer so that the
|
||||
different cases can have different keys.)
|
||||
|
||||
Example: another save menu entry was added
|
||||
|
||||
/* File: SomeWindow.m:314 */
|
||||
/* Comment: menu entry for saving a message */
|
||||
/* File: SomeOtherWindow.m:271 */
|
||||
/* Flag: untranslated */
|
||||
"Save..." = "Spara...";
|
||||
|
||||
The translation matches, so just remove the flag:
|
||||
|
||||
/* File: SomeWindow.m:314 */
|
||||
/* Comment: menu entry for saving a message */
|
||||
/* File: SomeOtherWindow.m:271 */
|
||||
"Save..." = "Spara...";
|
||||
|
||||
|
||||
If you're brave, you can use the '--aggressive-match' option. This
|
||||
option will make make_strings assume that matching keys should have
|
||||
matching translations, so it would have resolved the above example
|
||||
automatically. This can save lots of work, but it increases the risk of
|
||||
a mis-translation.
|
||||
|
||||
|
||||
/* Flag: unmatched */
|
||||
|
||||
This marks a string that existed in the .strings file, but not in the
|
||||
source. This might mean that the string has been removed, or that the
|
||||
string has changed so the match couldn't be found.
|
||||
|
||||
If the string was removed, simply remove the flag, the File: comment,
|
||||
the Comment: comment if it exists, and the key/value pair if it is no
|
||||
longer used.
|
||||
|
||||
Example: there used to be a load menu entry, but it has been removed
|
||||
|
||||
/* File: SomeWindow.m:127 */
|
||||
/* Flag: unmatched */
|
||||
"Open..." = "Öppna...";
|
||||
|
||||
The translation isn't used anymore, so remove all three lines.
|
||||
|
||||
|
||||
Example: one of the save menu entries was removed
|
||||
|
||||
/* File: SomeWindow.m:314 */
|
||||
/* Comment: menu entry for saving a message */
|
||||
/* Flag: unmatched */
|
||||
/* File: SomeOtherWindow.m:271 */
|
||||
"Save..." = "Spara...";
|
||||
|
||||
Again, remove the File:, Comment: and Flag:. However, the actual key/value
|
||||
pair is still used by the other location, so it should _not_ be removed.
|
||||
|
||||
/* File: SomeOtherWindow.m:271 */
|
||||
"Save..." = "Spara...";
|
||||
|
||||
|
||||
If code changes and a string is slightly changed or moved to a different
|
||||
file, there will probably be an untranslated string that matches the
|
||||
unmatched string (although make_strings hasn't been able to match them).
|
||||
|
||||
Example: someone changed the name of the save menu entry
|
||||
|
||||
/* File: SomeOtherWindow.m:271 */
|
||||
/* Flag: unmatched */
|
||||
"Save..." = "Spara...";
|
||||
|
||||
...
|
||||
|
||||
/* File: SomeOtherWindow.m:279 */
|
||||
/* Flag: untranslated */
|
||||
"Save data..." = "Save data...";
|
||||
|
||||
Update the translation, remove the untranslated flag, and remove the
|
||||
unmatched entry.
|
||||
|
||||
/* File: SomeOtherWindow.m:279 */
|
||||
"Save data..." = "Spara data...";
|
||||
|
||||
|
||||
4. Special cases
|
||||
================
|
||||
|
||||
4.1. Importing an existing .strings files
|
||||
-----------------------------------------
|
||||
|
||||
If your project already has a Localizable.strings (created by hand or
|
||||
something) and you want to use make_strings, you'll just need to run
|
||||
make_strings once to convert the files. Each old entry will appear as
|
||||
an unmatched entry from the file <dummy>, and each entry in the source
|
||||
will appear as an untranslated entry, so things will look like this:
|
||||
|
||||
/* File: <dummy>:0 */
|
||||
/* Flag: unmatched */
|
||||
/* File: Foo.m:183 */
|
||||
/* Flag: untranslated */
|
||||
"Close" = "Stäng";
|
||||
|
||||
It's easy (but boring) to check all the entries and remove the dummies
|
||||
and flags. make_strings is by default very careful and won't match things
|
||||
very well (after all, it can't be sure).
|
||||
|
||||
However, if you're fairly certain that the translation is OK, you can use
|
||||
the '--aggressive-import' option the first time you run make_strings. This
|
||||
option will make make_strings match much more aggressively, and it
|
||||
will greatly reduce the number of untranslated/unmatched strings in the
|
||||
resulting .strings file. (Eg. the above entry would appear as a single
|
||||
matched and translated entry.)
|
||||
|
||||
--aggressive-import works like --aggressive-match, but also removes any
|
||||
entries from the file <dummy> that were used to match an existing string.
|
||||
|
||||
|
33
Tools/make_strings/make_strings.h
Normal file
33
Tools/make_strings/make_strings.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* make_strings
|
||||
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Alexander Malmberg <alexander@malmberg.org>
|
||||
Created: 2002
|
||||
|
||||
This file is part of the GNUstep Project
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef make_strings_h
|
||||
#define make_strings_h
|
||||
|
||||
@class SourceEntry;
|
||||
|
||||
@interface NSMutableDictionary (make_strings)
|
||||
-(void) addEntry: (SourceEntry *)e toTable: (NSString *)table;
|
||||
@end
|
||||
|
||||
extern int verbose,aggressive_import,aggressive_match;
|
||||
|
||||
#endif
|
||||
|
554
Tools/make_strings/make_strings.m
Normal file
554
Tools/make_strings/make_strings.m
Normal file
|
@ -0,0 +1,554 @@
|
|||
/* make_strings
|
||||
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Alexander Malmberg <alexander@malmberg.org>
|
||||
Created: 2002
|
||||
|
||||
This file is part of the GNUstep Project
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <Foundation/NSObject.h>
|
||||
#include <Foundation/NSString.h>
|
||||
#include <Foundation/NSAutoreleasePool.h>
|
||||
#include <Foundation/NSDictionary.h>
|
||||
#include <Foundation/NSArray.h>
|
||||
|
||||
#include "make_strings.h"
|
||||
|
||||
#include "StringsFile.h"
|
||||
|
||||
#include "SourceEntry.h"
|
||||
#include "StringsEntry.h"
|
||||
|
||||
|
||||
int verbose,aggressive_import,aggressive_match;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *func_name;
|
||||
int num_args;
|
||||
int key_index,comment_index,table_index;
|
||||
} loc_func_t;
|
||||
|
||||
/*
|
||||
List of functions we should look for (easy to extend).
|
||||
*/
|
||||
static loc_func_t loc_funcs[]=
|
||||
{
|
||||
{"_" , 1, 0,-1,-1},
|
||||
{"NSLocalizedString" , 2, 0, 1,-1},
|
||||
{"NSLocalizedStringFromTable" , 3, 0, 2, 1},
|
||||
{"NSLocalizedStringFromTableInBundle" , 4, 0, 3, 1},
|
||||
|
||||
{"__" , 1, 0,-1,-1},
|
||||
{"NSLocalizedStaticString" , 2, 0, 1,-1},
|
||||
{},
|
||||
};
|
||||
#define MAX_ARGS 4
|
||||
|
||||
static int isname1(unsigned char ch)
|
||||
{
|
||||
if (ch=='_' || (ch>='a' && ch<='z') || (ch>='A' && ch<='Z')) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isname(unsigned char ch)
|
||||
{
|
||||
if (isname1(ch)) return 1;
|
||||
if (ch>='0' && ch<='9') return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This function attempts to parse the specified file and adds any calls to
|
||||
tables. To avoid excessive complexity and to easily handle comments and
|
||||
strings everywhere, it's written as a state machine.
|
||||
|
||||
Things that can fool it:
|
||||
- Stupid use of pre-processor stuff, like '#define foo bar('.
|
||||
Solution: Don't do that.
|
||||
|
||||
- Nested localization calls, like:
|
||||
'NSLocalizedString(@"foo",NSLocalizedString(@"bar",@"zot"))'.
|
||||
Solution: don't do that (with the current functions, there should never
|
||||
be any reason to).
|
||||
|
||||
*/
|
||||
static int ParseFile(const char *filename,NSMutableDictionary *tables)
|
||||
{
|
||||
FILE *f;
|
||||
NSString *filenamestr;
|
||||
|
||||
/*
|
||||
0: normal parsing
|
||||
1: in '//' comment
|
||||
2: in '/ *' comment
|
||||
3: in string
|
||||
5: parsing potentially interesting name
|
||||
6: parsing uninteresting name
|
||||
7: got name, wait for '('
|
||||
8: parsing arguments
|
||||
*/
|
||||
int state,old_state,skip;
|
||||
|
||||
int ch,nch;
|
||||
|
||||
int name=-1,nindex=0;
|
||||
|
||||
int cur_line;
|
||||
|
||||
unsigned char *args[MAX_ARGS];
|
||||
int arg_size[MAX_ARGS],arg_len[MAX_ARGS];
|
||||
int arg_ok[MAX_ARGS];
|
||||
int num_args;
|
||||
int i;
|
||||
|
||||
int depth=0;
|
||||
|
||||
static void add_arg_ch(int ch)
|
||||
{
|
||||
if (arg_len[num_args]+1>=arg_size[num_args])
|
||||
{
|
||||
arg_size[num_args]+=512;
|
||||
args[num_args]=realloc(args[num_args],arg_size[num_args]);
|
||||
if (!args[num_args])
|
||||
{
|
||||
NSLog(@"out of memory!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
args[num_args][arg_len[num_args]++]=ch;
|
||||
args[num_args][arg_len[num_args]]=0;
|
||||
}
|
||||
|
||||
|
||||
filenamestr=[NSString stringWithCString: filename];
|
||||
if (verbose)
|
||||
printf("Parsing '%s'.\n", [filenamestr cString]);
|
||||
f=fopen(filename,"rt");
|
||||
if (!f)
|
||||
{
|
||||
NSLog(@"Unable to open '%s': %m\n",filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
old_state=state=0;
|
||||
skip=0;
|
||||
cur_line=1;
|
||||
num_args=-1;
|
||||
|
||||
for (i=0;i<MAX_ARGS;i++)
|
||||
{
|
||||
args[i]=NULL;
|
||||
arg_size[i]=0;
|
||||
}
|
||||
|
||||
nch=fgetc(f);
|
||||
while (!feof(f))
|
||||
{
|
||||
ch=nch;
|
||||
if (ch==EOF) break;
|
||||
nch=fgetc(f);
|
||||
// printf("ch=%02x '%c' state=%i skip=%i\n",ch,ch,state,skip);
|
||||
if (skip)
|
||||
{
|
||||
skip--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch=='\n') cur_line++;
|
||||
|
||||
if (state==3)
|
||||
{
|
||||
if (ch!='"' && num_args!=-1 && arg_ok[num_args])
|
||||
add_arg_ch(ch);
|
||||
|
||||
if (ch=='\\')
|
||||
{
|
||||
if (num_args!=-1 && arg_ok[num_args])
|
||||
add_arg_ch(nch);
|
||||
skip=1;
|
||||
}
|
||||
else if (ch=='"')
|
||||
state=old_state;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (state==1)
|
||||
{
|
||||
if (ch=='\n' || ch=='\r')
|
||||
state=old_state;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (state==2)
|
||||
{
|
||||
if (ch=='*' && nch=='/')
|
||||
{
|
||||
state=old_state;
|
||||
skip=1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch=='"')
|
||||
{
|
||||
old_state=state;
|
||||
state=3;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch=='/' && nch=='/')
|
||||
{
|
||||
old_state=state;
|
||||
state=1;
|
||||
continue;
|
||||
}
|
||||
if (ch=='/' && nch=='*')
|
||||
{
|
||||
old_state=state;
|
||||
state=2;
|
||||
/* skip a character so we'll parse '/ * /' correctly */
|
||||
skip=1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (state==0 && isname1(ch))
|
||||
{
|
||||
for (name=0;loc_funcs[name].func_name;name++)
|
||||
if (ch==loc_funcs[name].func_name[0])
|
||||
break;
|
||||
if (loc_funcs[name].func_name)
|
||||
{
|
||||
state=5;
|
||||
nindex=1;
|
||||
}
|
||||
else
|
||||
state=6;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (state==6)
|
||||
{
|
||||
if (!isname(ch))
|
||||
state=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (state==5)
|
||||
{
|
||||
if (isname(ch))
|
||||
{
|
||||
int old_name;
|
||||
if (loc_funcs[name].func_name[nindex]==ch)
|
||||
{
|
||||
nindex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
old_name=name;
|
||||
for (name++;loc_funcs[name].func_name;name++)
|
||||
{
|
||||
if (!strncmp(loc_funcs[old_name].func_name,loc_funcs[name].func_name,nindex) &&
|
||||
loc_funcs[name].func_name[nindex]==ch)
|
||||
break;
|
||||
}
|
||||
if (loc_funcs[name].func_name)
|
||||
nindex++;
|
||||
else
|
||||
state=6;
|
||||
continue;
|
||||
}
|
||||
if (loc_funcs[name].func_name[nindex]!=0)
|
||||
{
|
||||
int old_name=name;
|
||||
for (name++;loc_funcs[name].func_name;name++)
|
||||
{
|
||||
if (!strncmp(loc_funcs[old_name].func_name,loc_funcs[name].func_name,nindex) &&
|
||||
loc_funcs[name].func_name[nindex]==0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!loc_funcs[name].func_name)
|
||||
{
|
||||
state=0;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// printf("found call to '%s' at line %i\n",loc_funcs[name].func_name,cur_line);
|
||||
state=7;
|
||||
}
|
||||
}
|
||||
|
||||
if (state==7)
|
||||
{
|
||||
if (ch=='(')
|
||||
{
|
||||
num_args=0;
|
||||
depth=0;
|
||||
state=8;
|
||||
for (i=0;i<MAX_ARGS;i++)
|
||||
{
|
||||
arg_len[i]=0;
|
||||
arg_ok[i]=1;
|
||||
}
|
||||
// printf(" start arg list, want %i args\n",loc_funcs[name].num_args);
|
||||
}
|
||||
else if (ch>32)
|
||||
state=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (state==8)
|
||||
{
|
||||
if (depth)
|
||||
{
|
||||
if (ch==')' || ch==']' || ch=='}')
|
||||
depth--;
|
||||
continue;
|
||||
}
|
||||
if (ch=='(' || ch=='[' || ch=='{')
|
||||
{
|
||||
arg_ok[num_args]=0;
|
||||
depth++;
|
||||
continue;
|
||||
}
|
||||
if (ch==')')
|
||||
{
|
||||
num_args++;
|
||||
|
||||
/* {
|
||||
printf("got call to '%s', %i args\n",loc_funcs[name].func_name,num_args);
|
||||
for (i=0;i<num_args;i++)
|
||||
printf(" %3i : %i '%s'\n",i,arg_ok[i],args[i]);
|
||||
}*/
|
||||
|
||||
{
|
||||
loc_func_t *lf=&loc_funcs[name];
|
||||
if (arg_ok[lf->key_index] &&
|
||||
(lf->comment_index==-1 || arg_ok[lf->comment_index]) &&
|
||||
(lf->table_index==-1 || arg_ok[lf->table_index]))
|
||||
{
|
||||
SourceEntry *e;
|
||||
NSString *key,*comment,*table;
|
||||
|
||||
/* TODO: let user specify source file encoding */
|
||||
key=[NSString stringWithCString: args[lf->key_index]];
|
||||
|
||||
if (lf->comment_index==-1 || !arg_len[lf->comment_index])
|
||||
comment=nil;
|
||||
else
|
||||
comment=[NSString stringWithCString: args[lf->comment_index]];
|
||||
|
||||
if (lf->table_index==-1)
|
||||
table=@"Localizable"; /* TODO: customizable? */
|
||||
else
|
||||
table=[NSString stringWithCString: args[lf->table_index]];
|
||||
|
||||
e=[[SourceEntry alloc] initWithKey: key comment: comment file: filenamestr line: cur_line];
|
||||
[tables addEntry: e toTable: table];
|
||||
[e release];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"unable to parse call to '%s' at %s:%i\n",lf->func_name,filename,cur_line);
|
||||
}
|
||||
}
|
||||
|
||||
num_args=-1;
|
||||
state=0;
|
||||
continue;
|
||||
}
|
||||
if (ch==',')
|
||||
{
|
||||
num_args++;
|
||||
if (num_args==MAX_ARGS)
|
||||
state=0;
|
||||
continue;
|
||||
}
|
||||
if (ch>32 && ch!='@')
|
||||
arg_ok[num_args]=0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0;i<MAX_ARGS;i++)
|
||||
if (args[i])
|
||||
free(args[i]);
|
||||
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@implementation NSMutableDictionary (make_strings)
|
||||
-(void) addEntry: (SourceEntry *)e toTable: (NSString *)table
|
||||
{
|
||||
NSMutableArray *a;
|
||||
a=[self objectForKey: table];
|
||||
if (!a)
|
||||
{
|
||||
a=[[NSMutableArray alloc] init];
|
||||
[self setObject: a forKey: table];
|
||||
[a release];
|
||||
}
|
||||
[a addObject: e];
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
static void UpdateTable(NSArray *source_table,NSString *filename)
|
||||
{
|
||||
int i,c;
|
||||
StringsFile *sf;
|
||||
|
||||
if (verbose)
|
||||
printf("Updating '%s'.\n", [filename cString]);
|
||||
sf=[[StringsFile alloc] initWithFile: filename];
|
||||
|
||||
c=[source_table count];
|
||||
for (i=0;i<c;i++)
|
||||
{
|
||||
[sf addSourceEntry: [source_table objectAtIndex: i]];
|
||||
}
|
||||
|
||||
[sf writeToFile: filename];
|
||||
DESTROY(sf);
|
||||
}
|
||||
|
||||
|
||||
static void HandleLanguage(NSString *language_name,NSMutableDictionary *source_entries)
|
||||
{
|
||||
CREATE_AUTORELEASE_POOL(arp);
|
||||
NSEnumerator *e;
|
||||
NSString *table_name;
|
||||
NSString *filename;
|
||||
|
||||
if (verbose)
|
||||
printf("Updating language '%s'.\n", [language_name cString]);
|
||||
for (e=[source_entries keyEnumerator];(table_name=[e nextObject]);)
|
||||
{
|
||||
filename=[[[NSString stringWithFormat: @"%@.lproj",language_name]
|
||||
stringByAppendingPathComponent:
|
||||
[NSString stringWithFormat: @"%@.strings",table_name]]
|
||||
stringByStandardizingPath];
|
||||
UpdateTable([source_entries objectForKey: table_name],filename);
|
||||
}
|
||||
|
||||
DESTROY(arp);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CREATE_AUTORELEASE_POOL(arp);
|
||||
|
||||
NSMutableDictionary *source_entries;
|
||||
|
||||
NSMutableArray *languages=[[NSMutableArray alloc] init];
|
||||
|
||||
int error;
|
||||
|
||||
{
|
||||
int i,j;
|
||||
char *c;
|
||||
for (j=i=1;i<argc;i++)
|
||||
{
|
||||
c=argv[i];
|
||||
if (!strcmp(c,"--help"))
|
||||
{
|
||||
printf("Syntax: %s [--help] [--verbose] [--aggressive-import] [--aggressive-match] [-L languages] files.[hmc...]\n",argv[0]);
|
||||
printf("\n");
|
||||
printf("Example: %s -L \"English Swedish German\" *.[hm]\n",argv[0]);
|
||||
return 0;
|
||||
}
|
||||
else if (!strcmp(c,"--verbose"))
|
||||
{
|
||||
verbose=1;
|
||||
}
|
||||
else if (!strcmp(c,"--aggressive-import"))
|
||||
{
|
||||
aggressive_import=1;
|
||||
aggressive_match=1;
|
||||
}
|
||||
else if (!strcmp(c,"--aggressive-match"))
|
||||
{
|
||||
aggressive_match=1;
|
||||
}
|
||||
else if (!strcmp(c,"-L"))
|
||||
{
|
||||
char *d,*d2;
|
||||
if (++i==argc)
|
||||
{
|
||||
NSLog(@"syntax error\n");
|
||||
return 1;
|
||||
}
|
||||
d=argv[i];
|
||||
while (1)
|
||||
{
|
||||
d2=strchr(d,' ');
|
||||
if (d2)
|
||||
*d2=0;
|
||||
[languages addObject: [NSString stringWithCString: d]];
|
||||
d=d2+1;
|
||||
if (!d2)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
argv[j++]=c;
|
||||
}
|
||||
}
|
||||
argc=j;
|
||||
}
|
||||
|
||||
if (![languages count])
|
||||
{
|
||||
NSLog(@"No languages specified!\n");
|
||||
return 1;
|
||||
}
|
||||
if (argc==1)
|
||||
{
|
||||
NSLog(@"No files specified!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
source_entries=[[NSMutableDictionary alloc] init];
|
||||
error=0;
|
||||
{
|
||||
int i;
|
||||
for (i=1;i<argc;i++)
|
||||
error+=ParseFile(argv[i],source_entries);
|
||||
}
|
||||
|
||||
if (!error)
|
||||
{
|
||||
int i,c=[languages count];
|
||||
for (i=0;i<c;i++)
|
||||
{
|
||||
HandleLanguage([languages objectAtIndex: i],source_entries);
|
||||
}
|
||||
}
|
||||
|
||||
DESTROY(arp);
|
||||
if (error)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
14
Tools/make_strings/test1.m
Normal file
14
Tools/make_strings/test1.m
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
_(@"foo") _ ( @"foo2" /* test */ )
|
||||
|
||||
"_()"
|
||||
|
||||
" \" _(foo) \" /* comment "
|
||||
|
||||
_ // test
|
||||
(@ /* comment " */ "test"
|
||||
@
|
||||
" test2"
|
||||
)
|
||||
|
||||
NSLocalizedString(@"Information", @"")
|
Loading…
Add table
Add a link
Reference in a new issue