haiku/headers/os/locale/Catalog.h
Adrien Destugues 76a4353b79 Add a new way of using the locale kit with static accessors instead of global variables. This has the following consequences :
* Applications don't have to declare BCatalog fCatalog themselves, it's now done automatically
 * Libs and add-ons can be localized just the same way (except static libraries)
For now this new system is yet disabled as I'm looking for some peer review before going on. To enable it you have to define B_TRANSLATE_USE_NEW_MACROS in each file doing catalog access. This will not stay, I'll update the 
other apps to use it.
The linking in jamfiles must be not only with liblocale.so, but also liblocalestub.a. Not sure how to handle this for user-side applications. Libraries are also required to provide a MIME signature to use any catalog.
The locale preflet is updated to the new system (as a test). Othe rapps will follow if everyone is ok with this approach.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37323 a95241bf-73f2-0310-859d-f6bbb57e9c96
2010-07-01 11:54:09 +00:00

385 lines
9.8 KiB
C++

/*
* Copyright 2003-2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#ifndef _CATALOG_H_
#define _CATALOG_H_
#include <SupportDefs.h>
#include <String.h>
class BCatalogAddOn;
class BLocale;
class BMessage;
struct entry_ref;
class BCatalog {
public:
BCatalog();
BCatalog(const char *signature, const char *language = NULL,
uint32 fingerprint = 0);
virtual ~BCatalog();
const char *GetString(const char *string, const char *context = NULL,
const char *comment = NULL);
const char *GetString(uint32 id);
status_t GetData(const char *name, BMessage *msg);
status_t GetData(uint32 id, BMessage *msg);
status_t GetSignature(BString *sig);
status_t GetLanguage(BString *lang);
status_t GetFingerprint(uint32 *fp);
status_t SetCatalog(const char* signature, uint32 fingerprint);
status_t InitCheck() const;
int32 CountItems() const;
BCatalogAddOn *CatalogAddOn();
protected:
BCatalog(const BCatalog&);
const BCatalog& operator= (const BCatalog&);
// hide assignment and copy-constructor
static status_t GetAppCatalog(BCatalog*);
BCatalogAddOn *fCatalog;
private:
friend class BLocale;
friend status_t get_add_on_catalog(BCatalog*, const char *);
};
extern BCatalog* be_catalog;
extern BCatalog* be_app_catalog;
// Proxy class for handling a "shared object local" catalog.
// This must be included (statically linked) into each shared object needing
// a catalog on its own (application, add-on, library, ...). The shared object
// must also have a mimetype so that the catalog can be identified.
class BCatalogStub {
private:
static BCatalog sCatalog;
static vint32 sCatalogInitOnce;
public:
static BCatalog* GetCatalog();
};
#ifndef B_AVOID_TRANSLATION_MACROS
// macros for easy catalog-access, define B_AVOID_TRANSLATION_MACROS if
// you don't want these:
#undef B_TRANSLATE_CONTEXT
// In a single application, several strings (e.g. 'Ok') will be used
// more than once, in different contexts.
// As the application programmer can not know if all translations of
// this string will be the same for all languages, each occurrence of
// the string must be translated on its own.
// Specifying the context explicitly with each string allows the person
// translating a catalog to separate these different occurrences of the
// same string and tell which strings appears in what context of the
// application.
// In order to give the translator a useful hint, the application
// programmer needs to define B_TRANSLATE_CONTEXT with the context he'd
// like to be associated with the strings used in this specifc source file.
// example:
// #define B_TRANSLATE_CONTEXT "Folder-Window"
// Tip: Use a descriptive name of the class implemented in that
// source-file.
#ifdef B_TRANSLATE_USE_NEW_MACROS
// Translation macros which may be used to shorten translation requests:
#undef B_TRANSLATE
#define B_TRANSLATE(str) \
BCatalogStub::GetCatalog()->GetString((str), B_TRANSLATE_CONTEXT)
#undef B_TRANSLATE_COMMENT
#define B_TRANSLATE_COMMENT(str, cmt) \
BCatalogStub::GetCatalog()->GetString((str), B_TRANSLATE_CONTEXT, (cmt))
#undef B_TRANSLATE_ALL
#define B_TRANSLATE_ALL(str, ctx, cmt) \
BCatalogStub::GetCatalog()->GetString((str), (ctx), (cmt))
#undef B_TRANSLATE_ID
#define B_TRANSLATE_ID(id) \
BCatalogStub::GetCatalog()->GetString((id))
#else
#define B_TRANSLATE(str) \
be_catalog->GetString((str), B_TRANSLATE_CONTEXT)
#undef B_TRANSLATE_COMMENT
#define B_TRANSLATE_COMMENT(str, cmt) \
be_catalog->GetString((str), B_TRANSLATE_CONTEXT, (cmt))
#undef B_TRANSLATE_ALL
#define B_TRANSLATE_ALL(str, ctx, cmt) \
be_catalog->GetString((str), (ctx), (cmt))
#undef B_TRANSLATE_ID
#define B_TRANSLATE_ID(id) \
be_catalog->GetString((id))
#endif
// Translation markers which can be used to mark static strings/IDs which
// are used as key for translation requests (at other places in the code):
/* example:
#define B_TRANSLATE_CONTEXT "MyDecentApp-Menu"
static const char *choices[] = {
B_TRANSLATE_MARK("left"),
B_TRANSLATE_MARK("right"),
B_TRANSLATE_MARK("up"),
B_TRANSLATE_MARK("down")
};
void MyClass::AddChoices(BMenu *menu) {
for (char **ch = choices; *ch; ch++) {
menu->AddItem(
new BMenuItem(
B_TRANSLATE(*ch),
new BMessage(...)
)
)
}
}
*/
#undef B_TRANSLATE_MARK
#define B_TRANSLATE_MARK(str) \
BCatalogAddOn::MarkForTranslation((str), B_TRANSLATE_CONTEXT, "")
#undef B_TRANSLATE_MARK_COMMENT
#define B_TRANSLATE_MARK_COMMENT(str, cmt) \
BCatalogAddOn::MarkForTranslation((str), B_TRANSLATE_CONTEXT, (cmt))
#undef B_TRANSLATE_MARK_ALL
#define B_TRANSLATE_MARK_ALL(str, ctx, cmt) \
BCatalogAddOn::MarkForTranslation((str), (ctx), (cmt))
#undef B_TRANSLATE_MARK_ID
#define B_TRANSLATE_MARK_ID(id) \
BCatalogAddOn::MarkForTranslation((id))
#endif /* B_AVOID_TRANSLATION_MACROS */
/************************************************************************/
// For BCatalog add-on implementations:
class BCatalogAddOn {
friend class BLocaleRoster;
public:
BCatalogAddOn(const char *signature, const char *language,
uint32 fingerprint);
virtual ~BCatalogAddOn();
virtual const char *GetString(const char *string,
const char *context = NULL,
const char *comment = NULL) = 0;
virtual const char *GetString(uint32 id) = 0;
status_t InitCheck() const;
BCatalogAddOn *Next();
// the following could be used to localize non-textual data (e.g.
// icons), but these will only be implemented if there's demand for such
// a feature:
virtual bool CanHaveData() const;
virtual status_t GetData(const char *name, BMessage *msg);
virtual status_t GetData(uint32 id, BMessage *msg);
// interface for catalog-editor-app and testing apps:
virtual status_t SetString(const char *string,
const char *translated,
const char *context = NULL,
const char *comment = NULL);
virtual status_t SetString(int32 id, const char *translated);
virtual bool CanWriteData() const;
virtual status_t SetData(const char *name, BMessage *msg);
virtual status_t SetData(uint32 id, BMessage *msg);
virtual status_t ReadFromFile(const char *path = NULL);
virtual status_t ReadFromAttribute(entry_ref *appOrAddOnRef);
virtual status_t ReadFromResource(entry_ref *appOrAddOnRef);
virtual status_t WriteToFile(const char *path = NULL);
virtual status_t WriteToAttribute(entry_ref *appOrAddOnRef);
virtual status_t WriteToResource(entry_ref *appOrAddOnRef);
virtual void MakeEmpty();
virtual int32 CountItems() const;
// magic marker functions which are used to mark a string/id
// which will be translated elsewhere in the code (where it can
// not be found since it is references by a variable):
static const char *MarkForTranslation(const char *str, const char *ctx,
const char *cmt);
static int32 MarkForTranslation(int32 id);
protected:
virtual void UpdateFingerprint();
status_t fInitCheck;
BString fSignature;
BString fLanguageName;
uint32 fFingerprint;
BCatalogAddOn *fNext;
friend class BCatalog;
friend status_t get_add_on_catalog(BCatalog*, const char *);
};
// every catalog-add-on should export these symbols...
// ...the function that instantiates a catalog for this add-on-type...
extern "C"
BCatalogAddOn *instantiate_catalog(const char *signature,
const char *language, uint32 fingerprint);
// ...the function that creates an empty catalog for this add-on-type...
extern "C"
BCatalogAddOn *create_catalog(const char *signature,
const char *language);
// ...and the priority which will be used to order the catalog-add-ons:
extern uint8 gCatalogAddOnPriority;
/*
* BCatalog - inlines for trivial accessors:
*/
inline status_t
BCatalog::GetSignature(BString *sig)
{
if (!sig)
return B_BAD_VALUE;
if (!fCatalog)
return B_NO_INIT;
*sig = fCatalog->fSignature;
return B_OK;
}
inline status_t
BCatalog::GetLanguage(BString *lang)
{
if (!lang)
return B_BAD_VALUE;
if (!fCatalog)
return B_NO_INIT;
*lang = fCatalog->fLanguageName;
return B_OK;
}
inline status_t
BCatalog::GetFingerprint(uint32 *fp)
{
if (!fp)
return B_BAD_VALUE;
if (!fCatalog)
return B_NO_INIT;
*fp = fCatalog->fFingerprint;
return B_OK;
}
inline status_t
BCatalog::InitCheck() const
{
return fCatalog
? fCatalog->InitCheck()
: B_NO_INIT;
}
inline int32
BCatalog::CountItems() const
{
if (!fCatalog)
return 0;
return fCatalog->CountItems();
}
inline BCatalogAddOn *
BCatalog::CatalogAddOn()
{
return fCatalog;
}
/*
* BCatalogAddOn - inlines for trivial accessors:
*/
inline BCatalogAddOn *
BCatalogAddOn::Next()
{
return fNext;
}
inline const char *
BCatalogAddOn::MarkForTranslation(const char *str, const char *ctx,
const char *cmt)
{
return str;
}
inline int32
BCatalogAddOn::MarkForTranslation(int32 id)
{
return id;
}
namespace BPrivate {
/*
* EditableCatalog
*/
class EditableCatalog : public BCatalog {
public:
EditableCatalog(const char *type, const char *signature,
const char *language);
~EditableCatalog();
status_t SetString(const char *string,
const char *translated,
const char *context = NULL,
const char *comment = NULL);
status_t SetString(int32 id, const char *translated);
bool CanWriteData() const;
status_t SetData(const char *name, BMessage *msg);
status_t SetData(uint32 id, BMessage *msg);
status_t ReadFromFile(const char *path = NULL);
status_t ReadFromAttribute(entry_ref *appOrAddOnRef);
status_t ReadFromResource(entry_ref *appOrAddOnRef);
status_t WriteToFile(const char *path = NULL);
status_t WriteToAttribute(entry_ref *appOrAddOnRef);
status_t WriteToResource(entry_ref *appOrAddOnRef);
void MakeEmpty();
private:
EditableCatalog();
EditableCatalog(const EditableCatalog&);
const EditableCatalog& operator= (const EditableCatalog&);
// hide assignment, default- and copy-constructor
};
} // namespace BPrivate
#endif /* _CATALOG_H_ */