fix for bug 172004 - provide a mechanism for embeddors to override specific strings in any string bundle with a single "string manifest" file.

r=tao, sr=sfraser, a=asa
This commit is contained in:
alecf%netscape.com 2002-10-14 19:06:27 +00:00
Родитель 9ab0709805
Коммит ddd2411b69
13 изменённых файлов: 720 добавлений и 270 удалений

Просмотреть файл

@ -302,7 +302,11 @@ static nsModuleComponentInfo components[] =
NS_HANKAKUTOZENKAKU_CONTRACTID, CreateNewHankakuToZenkaku},
// strres
{ "String Bundle", NS_STRINGBUNDLESERVICE_CID, NS_STRINGBUNDLE_CONTRACTID, nsStringBundleServiceConstructor},
{ "String Bundle", NS_STRINGBUNDLESERVICE_CID, NS_STRINGBUNDLE_CONTRACTID,
nsStringBundleServiceConstructor},
{ "String Textfile Overrides", NS_STRINGBUNDLETEXTOVERRIDE_CID,
NS_STRINGBUNDLETEXTOVERRIDE_CONTRACTID,
nsStringBundleTextOverrideConstructor },
// locale
{ "nsLocaleService component",

Просмотреть файл

@ -1201,6 +1201,13 @@
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsStringBundleTextOverride.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsCaseConversionImp2.cpp</PATH>
@ -1398,6 +1405,11 @@
<PATH>nsStringBundle.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsStringBundleTextOverride.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsCaseConversionImp2.cpp</PATH>
@ -2573,6 +2585,13 @@
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsStringBundleTextOverride.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsCaseConversionImp2.cpp</PATH>
@ -2770,6 +2789,11 @@
<PATH>nsStringBundle.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsStringBundleTextOverride.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsCaseConversionImp2.cpp</PATH>
@ -3024,6 +3048,12 @@
<PATH>nsStringBundle.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<TARGETNAME>i18n.shlb</TARGETNAME>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsStringBundleTextOverride.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
</GROUP>
<GROUP><NAME>Static Libs</NAME>
<FILEREF>

Просмотреть файл

@ -717,6 +717,13 @@
<FILEKIND>Text</FILEKIND>
<FILEFLAGS></FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIStringBundleOverride.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS></FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIAcceptLang.idl</PATH>
@ -731,6 +738,11 @@
<PATH>nsIStringBundle.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIStringBundleOverride.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIAcceptLang.idl</PATH>
@ -1402,6 +1414,13 @@
<FILEKIND>Text</FILEKIND>
<FILEFLAGS></FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIStringBundleOverride.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS></FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIAcceptLang.idl</PATH>
@ -1416,6 +1435,11 @@
<PATH>nsIStringBundle.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIStringBundleOverride.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIAcceptLang.idl</PATH>
@ -1437,6 +1461,12 @@
<PATH>nsIStringBundle.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<TARGETNAME>headers</TARGETNAME>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsIStringBundleOverride.idl</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<TARGETNAME>headers</TARGETNAME>
<PATHTYPE>Name</PATHTYPE>

Просмотреть файл

@ -28,7 +28,10 @@ include $(DEPTH)/config/autoconf.mk
MODULE = intl
XPIDLSRCS = nsIStringBundle.idl
XPIDLSRCS = \
nsIStringBundle.idl \
nsIStringBundleOverride.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
@ -85,9 +85,8 @@ interface nsIStringBundle : nsISupports
[scriptable, uuid(D85A17C0-AA7C-11d2-9B8C-00805F8A16D9)]
interface nsIStringBundleService : nsISupports
{
nsIStringBundle createBundle([const] in string aURLSpec);
nsIStringBundle createAsyncBundle([const] in string aURLSpec);
nsIStringBundle createExtensibleBundle([const] in string aRegistryKey);
nsIStringBundle createBundle(in string aURLSpec);
nsIStringBundle createExtensibleBundle(in string aRegistryKey);
/**
* Formats a message string from a status code and status arguments.

Просмотреть файл

@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is __________________________________________.
*
* The Initial Developer of the Original Code is
* ____________________________________________.
* Portions created by the Initial Developer are Copyright (C) 2___
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
interface nsISimpleEnumerator;
// to be implemented by an embeddor that wants to override some strings
[scriptable, uuid(965eb278-5678-456b-82a7-20a0c86a803c)]
interface nsIStringBundleOverride : nsISupports
{
/**
* get the override value for a particular key in a particular
* string bundle
*/
AString getStringFromName(in AUTF8String url,
in ACString key);
/**
* get all override keys for a given string bundle
*/
nsISimpleEnumerator enumerateKeysInBundle(in AUTF8String url);
};

Просмотреть файл

@ -36,7 +36,10 @@ REQUIRES = xpcom \
necko \
$(NULL)
CPPSRCS = nsStringBundle.cpp
CPPSRCS = \
nsStringBundle.cpp \
nsStringBundleTextOverride.cpp \
$(NULL)
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
@ -39,8 +39,10 @@
#ifndef nsStrBundleConstructors_h__
#define nsStrBundleConstructors_h__
#include "nsStringBundle.h"
#include "nsStringBundleService.h"
#include "nsStringBundleTextOverride.h"
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsStringBundleService, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsStringBundleTextOverride, Init)
#endif

Просмотреть файл

@ -42,9 +42,15 @@
#include "nsString.h"
#include "nsReadableUtils.h"
#include "nsIStringBundle.h"
#include "nsStringBundleService.h"
#include "nsStringBundle.h"
#include "nsStringBundleTextOverride.h"
#include "nsXPCOM.h"
#include "nsISupportsPrimitives.h"
#include "nsArray.h"
#include "nsArrayEnumerator.h"
#include "nscore.h"
#include "nsHashtable.h"
#include "nsMemory.h"
#include "plstr.h"
#include "nsNetUtil.h"
@ -56,7 +62,7 @@
#include "pratom.h"
#include "prmem.h"
#include "nsIModule.h"
#include "nsISupportsArray.h"
#include "nsCOMArray.h"
#include "nsAutoLock.h"
#include "nsTextFormatter.h"
#include "nsIErrorService.h"
@ -78,54 +84,14 @@
static NS_DEFINE_CID(kErrorServiceCID, NS_ERRORSERVICE_CID);
static NS_DEFINE_CID(kPersistentPropertiesCID, NS_IPERSISTENTPROPERTIES_CID);
// XXX investigate need for proper locking in this module
//static PRInt32 gLockCount = 0;
NS_DEFINE_IID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
class nsStringBundle : public nsIStringBundle
#ifdef ASYNC_LOADING
, public nsIStreamLoaderObserver
#endif
{
public:
// init version
nsStringBundle(const char* aURLSpec);
nsresult LoadProperties();
virtual ~nsStringBundle();
NS_DECL_ISUPPORTS
NS_DECL_NSISTRINGBUNDLE
#ifdef ASYNC_LOADING
NS_DECL_NSISTREAMLOADEROBSERVER
#endif
nsCOMPtr<nsIPersistentProperties> mProps;
protected:
//
// functional decomposition of the funitions repeatively called
//
nsresult GetStringFromID(PRInt32 aID, nsAString& aResult);
nsresult GetStringFromName(const nsAString& aName, nsAString& aResult);
private:
nsCString mPropertiesURL;
PRPackedBool mAttemptedLoad;
PRPackedBool mLoaded;
public:
static nsresult FormatString(const PRUnichar *formatStr,
const PRUnichar **aParams, PRUint32 aLength,
PRUnichar **aResult);
};
nsStringBundle::~nsStringBundle()
{
}
nsStringBundle::nsStringBundle(const char* aURLSpec) :
nsStringBundle::nsStringBundle(const char* aURLSpec,
nsIStringBundleOverride* aOverrideStrings) :
mPropertiesURL(aURLSpec),
mOverrideStrings(aOverrideStrings),
mAttemptedLoad(PR_FALSE),
mLoaded(PR_FALSE)
{
@ -150,142 +116,31 @@ nsStringBundle::LoadProperties()
nsresult rv;
// to be turned on once we figure out how to ensure we're loading on
// the main thread
#ifdef ASYNC_LOADING
// load the string bundle asynchronously on another thread,
// but make sure we block this thread so that LoadProperties() is
// synchronous
// create an event queue for this thread.
nsCOMPtr<nsIEventQueueService> service = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIEventQueue> currentThreadQ;
rv = service->PushThreadEventQueue(getter_AddRefs(currentThreadQ));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
// do it synchronously
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), mPropertiesURL);
if (NS_FAILED(rv)) return rv;
// create and loader, then wait
nsCOMPtr<nsIStreamLoader> loader;
rv = NS_NewStreamLoader(getter_AddRefs(loader),
uri,
this /*the load observer*/);
NS_ASSERTION(NS_SUCCEEDED(rv), "\n-->nsStringBundle::Init: NS_NewStreamLoader failed...\n");
// process events until we're finished.
PLEvent *event;
while (!mLoaded) {
rv = currentThreadQ->WaitForEvent(&event);
NS_ASSERTION(NS_SUCCEEDED(rv), "\n-->nsStringBundle::Init: currentThreadQ->WaitForEvent failed...\n");
if (NS_FAILED(rv)) break;
rv = currentThreadQ->HandleEvent(event);
NS_ASSERTION(NS_SUCCEEDED(rv), "\n-->nsStringBundle::Init: currentThreadQ->HandleEvent failed...\n");
if (NS_FAILED(rv)) break;
}
rv = service->PopThreadEventQueue(currentThreadQ);
#else
// do it synchronously
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), mPropertiesURL);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIInputStream> in;
rv = NS_OpenURI(getter_AddRefs(in), uri);
if (NS_FAILED(rv)) return rv;
NS_TIMELINE_MARK_FUNCTION("loading properties");
NS_ASSERTION(NS_SUCCEEDED(rv) && in, "Error in OpenBlockingStream");
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && in, NS_ERROR_FAILURE);
mProps = do_CreateInstance(kPersistentPropertiesCID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
mAttemptedLoad = mLoaded = PR_TRUE;
rv = mProps->Load(in);
mLoaded = NS_SUCCEEDED(rv);
#endif
return rv;
}
#ifdef ASYNC_LOADING
NS_IMETHODIMP
nsStringBundle::OnStreamComplete(nsIStreamLoader* aLoader,
nsISupports* context,
nsresult aStatus,
PRUint32 stringLen,
const char* string)
{
nsXPIDLCString uriSpec;
if (NS_FAILED(aStatus)) {
// print a load error on bad status
#if defined(DEBUG)
if (aLoader) {
nsCOMPtr<nsIRequest> request;
aLoader->GetRequest(getter_AddRefs(request));
nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
if (channel) {
nsCOMPtr<nsIURI> uri;
channel->GetURI(getter_AddRefs(uri));
if (uri) {
uri->GetSpec(getter_Copies(uriSpec));
printf("\n -->nsStringBundle::OnStreamComplete: Failed to load %s\n",
uriSpec ? (const char *) uriSpec : "");
}
}
}
#endif
return aStatus;
}
nsresult rv;
nsCOMPtr<nsISupports> stringStreamSupports;
rv = NS_NewByteInputStream(getter_AddRefs(stringStreamSupports),
string, stringLen);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIInputStream> in = do_QueryInterface(stringStreamSupports, &rv);
nsCOMPtr<nsIInputStream> in;
rv = NS_OpenURI(getter_AddRefs(in), uri);
if (NS_FAILED(rv)) return rv;
NS_TIMELINE_MARK_FUNCTION("loading properties");
NS_ASSERTION(NS_SUCCEEDED(rv) && in, "Error in OpenBlockingStream");
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && in, NS_ERROR_FAILURE);
mProps = do_CreateInstance(kPersistentPropertiesCID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// load the stream
mAttemptedLoad = mLoaded = PR_TRUE;
rv = mProps->Load(in);
mLoaded = NS_SUCCEEDED(rv);
//
// notify
if (NS_SUCCEEDED(rv)) {
mLoaded = PR_TRUE;
// observer notification
nsCOMPtr<nsIObserverService> os = do_GetService("@mozilla.org/observer-service;1");
if (os)
(void) os->NotifyObservers((nsIStringBundle *) this,
NS_STRBUNDLE_LOADED_TOPIC,
nsnull);
#if defined(DEBUG_tao)
printf("\n --> nsStringBundle::OnStreamComplete: end sending NOTIFICATIONS!!\n");
#endif
}
return rv;
}
#endif
nsresult
nsStringBundle::GetStringFromID(PRInt32 aID, nsAString& aResult)
@ -293,7 +148,18 @@ nsStringBundle::GetStringFromID(PRInt32 aID, nsAString& aResult)
nsAutoCMonitor(this);
nsCAutoString name;
name.AppendInt(aID, 10);
nsresult rv = mProps->GetStringProperty(name, aResult);
nsresult rv;
// try override first
if (mOverrideStrings) {
rv = mOverrideStrings->GetStringFromName(mPropertiesURL,
name,
aResult);
if (NS_SUCCEEDED(rv)) return rv;
}
rv = mProps->GetStringProperty(name, aResult);
#ifdef DEBUG_tao_
char *s = ToNewCString(aResult);
@ -311,6 +177,14 @@ nsStringBundle::GetStringFromName(const nsAString& aName,
{
nsresult rv;
// try override first
if (mOverrideStrings) {
rv = mOverrideStrings->GetStringFromName(mPropertiesURL,
NS_ConvertUCS2toUTF8(aName),
aResult);
if (NS_SUCCEEDED(rv)) return rv;
}
rv = mProps->GetStringProperty(NS_ConvertUCS2toUTF8(aName), aResult);
#ifdef DEBUG_tao_
char *s = ToNewCString(aResult),
@ -353,13 +227,8 @@ nsStringBundle::FormatStringFromName(const PRUnichar *aName,
}
#ifdef ASYNC_LOADING
NS_IMPL_THREADSAFE_ISUPPORTS2(nsStringBundle,
nsIStringBundle, nsIStreamLoaderObserver)
#else
NS_IMPL_THREADSAFE_ISUPPORTS1(nsStringBundle,
nsIStringBundle)
#endif
/* void GetStringFromID (in long aID, out wstring aResult); */
NS_IMETHODIMP
@ -396,6 +265,67 @@ nsStringBundle::GetStringFromName(const PRUnichar *aName, PRUnichar **aResult)
return rv;
}
nsresult
nsStringBundle::GetCombinedEnumeration(nsISimpleEnumerator* aOverrideEnumerator,
nsISimpleEnumerator** aResult)
{
nsCOMPtr<nsISupports> supports;
nsCOMPtr<nsIPropertyElement> propElement;
nsresult rv;
PRBool hasMore;
nsCOMPtr<nsIMutableArray> resultArray;
NS_NewArray(getter_AddRefs(resultArray));
// first, append the override elements only if
// they don't already exist in mProps
do {
rv = aOverrideEnumerator->GetNext(getter_AddRefs(supports));
if (NS_SUCCEEDED(rv) &&
(propElement = do_QueryInterface(supports, &rv))) {
nsCAutoString key;
rv = propElement->GetKey(key);
if (NS_SUCCEEDED(rv)) {
PRBool hasKey;
mProps->Has(key.get(), &hasKey);
if (!hasKey)
resultArray->AppendElement(propElement, PR_FALSE);
}
}
aOverrideEnumerator->HasMoreElements(&hasMore);
} while (hasMore);
// ok, now we have the "unique" elements in resultArray
nsCOMPtr<nsISimpleEnumerator> propEnumerator;
rv = mProps->Enumerate(getter_AddRefs(propEnumerator));
if (NS_FAILED(rv)) {
// no elements in mProps anyway, just return what we have
return NS_NewArrayEnumerator(aResult, resultArray);
}
// second, append all the elements that are in mProps
do {
rv = propEnumerator->GetNext(getter_AddRefs(supports));
if (NS_SUCCEEDED(rv) &&
(propElement = do_QueryInterface(supports, &rv)))
resultArray->AppendElement(propElement, PR_FALSE);
propEnumerator->HasMoreElements(&hasMore);
} while (hasMore);
NS_ADDREF(*aResult = propEnumerator);
return NS_OK;
}
NS_IMETHODIMP
nsStringBundle::GetSimpleEnumeration(nsISimpleEnumerator** elements)
{
@ -406,6 +336,14 @@ nsStringBundle::GetSimpleEnumeration(nsISimpleEnumerator** elements)
rv = LoadProperties();
if (NS_FAILED(rv)) return rv;
if (mOverrideStrings) {
nsCOMPtr<nsISimpleEnumerator> overrideEnumerator;
rv = mOverrideStrings->EnumerateKeysInBundle(mPropertiesURL,
getter_AddRefs(overrideEnumerator));
if (NS_SUCCEEDED(rv))
return GetCombinedEnumeration(overrideEnumerator, elements);
}
return mProps->Enumerate(elements);
}
@ -438,39 +376,13 @@ nsStringBundle::FormatString(const PRUnichar *aFormatStr,
return NS_OK;
}
/**
* An extesible implementation of the StringBudle interface.
*
* @created 28/Dec/1999
* @author Catalin Rotaru [CATA]
*/
class nsExtensibleStringBundle : public nsIStringBundle
{
NS_DECL_ISUPPORTS
NS_DECL_NSISTRINGBUNDLE
nsresult Init(const char * aCategory, nsIStringBundleService *);
private:
nsISupportsArray * mBundle;
PRBool mLoaded;
public:
nsExtensibleStringBundle();
virtual ~nsExtensibleStringBundle();
};
NS_IMPL_ISUPPORTS1(nsExtensibleStringBundle, nsIStringBundle)
nsExtensibleStringBundle::nsExtensibleStringBundle()
:mBundle(NULL)
{
NS_INIT_ISUPPORTS();
mLoaded = PR_FALSE;
}
nsresult
@ -487,10 +399,6 @@ nsExtensibleStringBundle::Init(const char * aCategory,
rv = catman->EnumerateCategory(aCategory, getter_AddRefs(enumerator));
if (NS_FAILED(rv)) return rv;
// create the bundles array
rv = NS_NewISupportsArray(&mBundle);
if (NS_FAILED(rv)) return rv;
PRBool hasMore;
while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsISupports> supports;
@ -512,7 +420,7 @@ nsExtensibleStringBundle::Init(const char * aCategory,
if (NS_FAILED(rv))
continue;
mBundle->AppendElement(bundle);
mBundles.AppendObject(bundle);
}
return rv;
@ -520,7 +428,6 @@ nsExtensibleStringBundle::Init(const char * aCategory,
nsExtensibleStringBundle::~nsExtensibleStringBundle()
{
NS_IF_RELEASE(mBundle);
}
nsresult nsExtensibleStringBundle::GetStringFromID(PRInt32 aID, PRUnichar ** aResult)
@ -529,13 +436,11 @@ nsresult nsExtensibleStringBundle::GetStringFromID(PRInt32 aID, PRUnichar ** aRe
PRUint32 size, i;
rv = mBundle->Count(&size);
if (NS_FAILED(rv)) return rv;
size = mBundles.Count();
for (i = 0; i < size; i++) {
nsCOMPtr<nsIStringBundle> bundle;
rv = mBundle->QueryElementAt(i, NS_GET_IID(nsIStringBundle), getter_AddRefs(bundle));
if (NS_SUCCEEDED(rv)) {
nsIStringBundle *bundle = mBundles[i];
if (bundle) {
rv = bundle->GetStringFromID(aID, aResult);
if (NS_SUCCEEDED(rv))
return NS_OK;
@ -551,13 +456,11 @@ nsresult nsExtensibleStringBundle::GetStringFromName(const PRUnichar *aName,
nsresult res = NS_OK;
PRUint32 size, i;
res = mBundle->Count(&size);
if (NS_FAILED(res)) return res;
size = mBundles.Count();
for (i = 0; i < size; i++) {
nsCOMPtr<nsIStringBundle> bundle;
res = mBundle->QueryElementAt(i, NS_GET_IID(nsIStringBundle), getter_AddRefs(bundle));
if (NS_SUCCEEDED(res)) {
nsIStringBundle* bundle = mBundles[i];
if (bundle) {
res = bundle->GetStringFromName(aName, aResult);
if (NS_SUCCEEDED(res))
return NS_OK;
@ -647,6 +550,11 @@ nsStringBundleService::Init()
os->AddObserver(this, "profile-do-change", PR_TRUE);
}
// instantiate the override service, if there is any.
// at some point we probably want to make this a category, and
// support multiple overrides
mOverrideStrings = do_GetService(NS_STRINGBUNDLETEXTOVERRIDE_CONTRACTID);
return NS_OK;
}
@ -706,7 +614,7 @@ nsStringBundleService::getStringBundle(const char *aURLSpec,
} else {
// hasn't been cached, so insert it into the hash table
nsStringBundle* bundle = new nsStringBundle(aURLSpec);
nsStringBundle* bundle = new nsStringBundle(aURLSpec, mOverrideStrings);
if (!bundle) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(bundle);
@ -798,12 +706,6 @@ nsStringBundleService::CreateBundle(const char* aURLSpec,
return getStringBundle(aURLSpec,aResult);
}
NS_IMETHODIMP
nsStringBundleService::CreateAsyncBundle(const char* aURLSpec, nsIStringBundle** aResult)
{
return getStringBundle(aURLSpec, aResult);
}
NS_IMETHODIMP
nsStringBundleService::CreateExtensibleBundle(const char* aCategory,
nsIStringBundle** aResult)

Просмотреть файл

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
@ -39,52 +39,70 @@
#ifndef nsStringBundle_h__
#define nsStringBundle_h__
#include "prclist.h"
#include "plarena.h"
#include "nsCOMPtr.h"
#include "nsHashtable.h"
#include "nsIPersistentProperties2.h"
#include "nsIStringBundle.h"
#include "nsIObserver.h"
#include "nsWeakReference.h"
#include "nsIErrorService.h"
#include "nsCOMPtr.h"
#include "nsIPersistentProperties2.h"
#include "nsString.h"
#include "nsCOMArray.h"
#include "nsIStringBundleOverride.h"
struct bundleCacheEntry_t;
class nsStringBundleService : public nsIStringBundleService,
public nsIObserver,
public nsSupportsWeakReference
class nsStringBundle : public nsIStringBundle
{
public:
nsStringBundleService();
virtual ~nsStringBundleService();
// init version
nsStringBundle(const char* aURLSpec, nsIStringBundleOverride*);
nsresult LoadProperties();
virtual ~nsStringBundle();
NS_DECL_ISUPPORTS
NS_DECL_NSISTRINGBUNDLE
nsresult Init();
nsCOMPtr<nsIPersistentProperties> mProps;
NS_DECL_ISUPPORTS
NS_DECL_NSISTRINGBUNDLESERVICE
NS_DECL_NSIOBSERVER
protected:
//
// functional decomposition of the funitions repeatively called
//
nsresult GetStringFromID(PRInt32 aID, nsAString& aResult);
nsresult GetStringFromName(const nsAString& aName, nsAString& aResult);
nsresult GetCombinedEnumeration(nsISimpleEnumerator* aOverrideEnumerator,
nsISimpleEnumerator** aResult);
private:
nsresult getStringBundle(const char *aUrl, nsIStringBundle** aResult);
nsresult FormatWithBundle(nsIStringBundle* bundle, nsresult aStatus,
PRUint32 argCount, PRUnichar** argArray,
PRUnichar* *result);
void flushBundleCache();
bundleCacheEntry_t *insertIntoCache(nsIStringBundle *aBundle,
nsCStringKey *aHashKey);
static void recycleEntry(bundleCacheEntry_t*);
nsHashtable mBundleMap;
PRCList mBundleCache;
PLArenaPool mCacheEntryPool;
nsCOMPtr<nsIErrorService> mErrorService;
nsCString mPropertiesURL;
nsCOMPtr<nsIStringBundleOverride> mOverrideStrings;
PRPackedBool mAttemptedLoad;
PRPackedBool mLoaded;
public:
static nsresult FormatString(const PRUnichar *formatStr,
const PRUnichar **aParams, PRUint32 aLength,
PRUnichar **aResult);
};
/**
* An extesible implementation of the StringBudle interface.
*
* @created 28/Dec/1999
* @author Catalin Rotaru [CATA]
*/
class nsExtensibleStringBundle : public nsIStringBundle
{
NS_DECL_ISUPPORTS
NS_DECL_NSISTRINGBUNDLE
nsresult Init(const char * aCategory, nsIStringBundleService *);
private:
nsCOMArray<nsIStringBundle> mBundles;
PRBool mLoaded;
public:
nsExtensibleStringBundle();
virtual ~nsExtensibleStringBundle();
};
#endif

Просмотреть файл

@ -0,0 +1,91 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsStringBundleService_h__
#define nsStringBundleService_h__
#include "prclist.h"
#include "plarena.h"
#include "nsCOMPtr.h"
#include "nsHashtable.h"
#include "nsIPersistentProperties2.h"
#include "nsIStringBundle.h"
#include "nsIObserver.h"
#include "nsWeakReference.h"
#include "nsIErrorService.h"
#include "nsIStringBundleOverride.h"
struct bundleCacheEntry_t;
class nsStringBundleService : public nsIStringBundleService,
public nsIObserver,
public nsSupportsWeakReference
{
public:
nsStringBundleService();
virtual ~nsStringBundleService();
nsresult Init();
NS_DECL_ISUPPORTS
NS_DECL_NSISTRINGBUNDLESERVICE
NS_DECL_NSIOBSERVER
private:
nsresult getStringBundle(const char *aUrl, nsIStringBundle** aResult);
nsresult FormatWithBundle(nsIStringBundle* bundle, nsresult aStatus,
PRUint32 argCount, PRUnichar** argArray,
PRUnichar* *result);
void flushBundleCache();
bundleCacheEntry_t *insertIntoCache(nsIStringBundle *aBundle,
nsCStringKey *aHashKey);
static void recycleEntry(bundleCacheEntry_t*);
nsHashtable mBundleMap;
PRCList mBundleCache;
PLArenaPool mCacheEntryPool;
nsCOMPtr<nsIErrorService> mErrorService;
nsCOMPtr<nsIStringBundleOverride> mOverrideStrings;
};
#endif

Просмотреть файл

@ -0,0 +1,237 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the string bundle override service.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alec Flett <alecf@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsStringBundleTextOverride.h"
#include "nsString.h"
#include "nsEscape.h"
#include "nsNetUtil.h"
#include "nsAppDirectoryServiceDefs.h"
static NS_DEFINE_CID(kPersistentPropertiesCID, NS_IPERSISTENTPROPERTIES_CID);
class nsPropertyEnumeratorByURL : public nsISimpleEnumerator
{
public:
nsPropertyEnumeratorByURL(const nsACString& aURL,
nsISimpleEnumerator* aOuter) :
mURL(aURL),
mOuter(aOuter)
{
// persistent properties uses ":" as a delimiter, so escape
// that character
mURL.ReplaceSubstring(":", "%3A");
// append the hash mark now, so we don't have to add it after each
// compare
mURL.Append('#');
}
NS_DECL_ISUPPORTS
NS_DECL_NSISIMPLEENUMERATOR
virtual ~nsPropertyEnumeratorByURL() {}
private:
// actual enumerator of all strings from nsIProperties
nsCOMPtr<nsISimpleEnumerator> mOuter;
nsCOMPtr<nsIPropertyElement> mCurrent;
nsCString mURL;
};
//
// nsStringBundleTextOverride implementation
//
NS_IMPL_ISUPPORTS1(nsStringBundleTextOverride,
nsIStringBundleOverride)
nsresult
nsStringBundleTextOverride::Init()
{
nsresult rv;
// check for existence of custom-strings.txt
nsCOMPtr<nsIFile> customStringsFile;
rv = NS_GetSpecialDirectory(NS_APP_CHROME_DIR,
getter_AddRefs(customStringsFile));
if (NS_FAILED(rv)) return rv;
// bail if not found - this will cause the service creation to
// bail as well, and cause this object to go away
customStringsFile->AppendNative(NS_LITERAL_CSTRING("custom-strings.txt"));
PRBool exists;
rv = customStringsFile->Exists(&exists);
if (NS_FAILED(rv) || !exists)
return NS_ERROR_FAILURE;
NS_WARNING("Using custom-strings.txt to override string bundles.");
// read in the custom bundle. Keys are in the form
// chrome://package/locale/foo.properties:keyname
nsCAutoString customStringsURLSpec;
rv = NS_GetURLSpecFromFile(customStringsFile, customStringsURLSpec);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), customStringsURLSpec);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIInputStream> in;
rv = NS_OpenURI(getter_AddRefs(in), uri);
if (NS_FAILED(rv)) return rv;
mValues = do_CreateInstance(kPersistentPropertiesCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = mValues->Load(in);
// turn this on to see the contents of custom-strings.txt
#ifdef DEBUG_alecf
nsCOMPtr<nsISimpleEnumerator> enumerator;
mValues->Enumerate(getter_AddRefs(enumerator));
NS_ASSERTION(enumerator, "no enumerator!\n");
printf("custom-strings.txt contains:\n");
printf("----------------------------\n");
PRBool hasMore;
enumerator->HasMoreElements(&hasMore);
do {
nsCOMPtr<nsISupports> sup;
enumerator->GetNext(getter_AddRefs(sup));
nsCOMPtr<nsIPropertyElement> prop = do_QueryInterface(sup);
nsCAutoString key;
nsAutoString value;
prop->GetKey(key);
prop->GetValue(value);
printf("%s = '%s'\n", key.get(), NS_ConvertUCS2toUTF8(value).get());
enumerator->HasMoreElements(&hasMore);
} while (hasMore);
#endif
return rv;
}
NS_IMETHODIMP
nsStringBundleTextOverride::GetStringFromName(const nsACString& aURL,
const nsACString& key,
nsAString& aResult)
{
// concatenate url#key to get the key to read
nsCAutoString combinedURL(aURL + NS_LITERAL_CSTRING("#") + key);
// persistent properties uses ":" as a delimiter, so escape that character
combinedURL.ReplaceSubstring(":", "%3A");
return mValues->GetStringProperty(combinedURL, aResult);
}
NS_IMETHODIMP
nsStringBundleTextOverride::EnumerateKeysInBundle(const nsACString& aURL,
nsISimpleEnumerator** aResult)
{
// enumerate all strings, and let the enumerator know
nsCOMPtr<nsISimpleEnumerator> enumerator;
mValues->Enumerate(getter_AddRefs(enumerator));
// make the enumerator wrapper and pass it off
nsPropertyEnumeratorByURL* propEnum =
new nsPropertyEnumeratorByURL(aURL, enumerator);
if (!propEnum) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult = propEnum);
return NS_OK;
}
//
// nsPropertyEnumeratorByURL implementation
//
NS_IMPL_ISUPPORTS1(nsPropertyEnumeratorByURL, nsISimpleEnumerator)
NS_IMETHODIMP
nsPropertyEnumeratorByURL::GetNext(nsISupports **aResult)
{
if (!mCurrent) return NS_ERROR_UNEXPECTED;
NS_ADDREF(*aResult = mCurrent);
return NS_OK;
}
NS_IMETHODIMP
nsPropertyEnumeratorByURL::HasMoreElements(PRBool * aResult)
{
PRBool hasMore;
do {
nsCOMPtr<nsISupports> supports;
mOuter->GetNext(getter_AddRefs(supports));
mCurrent = do_QueryInterface(supports);
if (mCurrent) {
nsCAutoString curKey;
mCurrent->GetKey(curKey);
if (mURL.Equals(Substring(curKey, 0, mURL.Length())))
break;
}
mOuter->HasMoreElements(&hasMore);
} while (hasMore);
if (!hasMore)
mCurrent = PR_FALSE;
*aResult = mCurrent ? PR_TRUE : PR_FALSE;
return NS_OK;
}

Просмотреть файл

@ -0,0 +1,74 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the string bundle override service.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alec Flett <alecf@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsStringBundleTextOverride_h__
#define nsStringBundleTextOverride_h__
#include "nsIStringBundleOverride.h"
#include "nsCOMPtr.h"
#include "nsIPersistentProperties2.h"
// {6316C6CE-12D3-479e-8F53-E289351412B8}
#define NS_STRINGBUNDLETEXTOVERRIDE_CID \
{ 0x6316c6ce, 0x12d3, 0x479e, \
{ 0x8f, 0x53, 0xe2, 0x89, 0x35, 0x14, 0x12, 0xb8 } }
#define NS_STRINGBUNDLETEXTOVERRIDE_CONTRACTID \
"@mozilla.org/intl/stringbundle/text-override;1"
// an implementation which does overrides from a text file
class nsStringBundleTextOverride : public nsIStringBundleOverride
{
public:
nsStringBundleTextOverride() { NS_INIT_ISUPPORTS(); }
virtual ~nsStringBundleTextOverride() {}
nsresult Init();
NS_DECL_ISUPPORTS
NS_DECL_NSISTRINGBUNDLEOVERRIDE
private:
nsCOMPtr<nsIPersistentProperties> mValues;
};
#endif