207 lines
6.6 KiB
C++
207 lines
6.6 KiB
C++
/*
|
|
==============================================================================
|
|
|
|
This file is part of the JUCE library.
|
|
Copyright (c) 2017 - ROLI Ltd.
|
|
|
|
JUCE is an open source library subject to commercial or open-source
|
|
licensing.
|
|
|
|
The code included in this file is provided under the terms of the ISC license
|
|
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
|
To use, copy, modify, and/or distribute this software for any purpose with or
|
|
without fee is hereby granted provided that the above copyright notice and
|
|
this permission notice appear in all copies.
|
|
|
|
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
|
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
|
DISCLAIMED.
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
namespace juce
|
|
{
|
|
|
|
LocalisedStrings::LocalisedStrings (const String& fileContents, bool ignoreCase)
|
|
{
|
|
loadFromText (fileContents, ignoreCase);
|
|
}
|
|
|
|
LocalisedStrings::LocalisedStrings (const File& fileToLoad, bool ignoreCase)
|
|
{
|
|
loadFromText (fileToLoad.loadFileAsString(), ignoreCase);
|
|
}
|
|
|
|
LocalisedStrings::LocalisedStrings (const LocalisedStrings& other)
|
|
: languageName (other.languageName), countryCodes (other.countryCodes),
|
|
translations (other.translations), fallback (createCopyIfNotNull (other.fallback.get()))
|
|
{
|
|
}
|
|
|
|
LocalisedStrings& LocalisedStrings::operator= (const LocalisedStrings& other)
|
|
{
|
|
languageName = other.languageName;
|
|
countryCodes = other.countryCodes;
|
|
translations = other.translations;
|
|
fallback.reset (createCopyIfNotNull (other.fallback.get()));
|
|
return *this;
|
|
}
|
|
|
|
LocalisedStrings::~LocalisedStrings()
|
|
{
|
|
}
|
|
|
|
//==============================================================================
|
|
String LocalisedStrings::translate (const String& text) const
|
|
{
|
|
if (fallback != nullptr && ! translations.containsKey (text))
|
|
return fallback->translate (text);
|
|
|
|
return translations.getValue (text, text);
|
|
}
|
|
|
|
String LocalisedStrings::translate (const String& text, const String& resultIfNotFound) const
|
|
{
|
|
if (fallback != nullptr && ! translations.containsKey (text))
|
|
return fallback->translate (text, resultIfNotFound);
|
|
|
|
return translations.getValue (text, resultIfNotFound);
|
|
}
|
|
|
|
namespace
|
|
{
|
|
#if JUCE_CHECK_MEMORY_LEAKS
|
|
// By using this object to force a LocalisedStrings object to be created
|
|
// before the currentMappings object, we can force the static order-of-destruction to
|
|
// delete the currentMappings object first, which avoids a bogus leak warning.
|
|
// (Oddly, just creating a LocalisedStrings on the stack doesn't work in gcc, it
|
|
// has to be created with 'new' for this to work..)
|
|
struct LeakAvoidanceTrick
|
|
{
|
|
LeakAvoidanceTrick()
|
|
{
|
|
const std::unique_ptr<LocalisedStrings> dummy (new LocalisedStrings (String(), false));
|
|
}
|
|
};
|
|
|
|
LeakAvoidanceTrick leakAvoidanceTrick;
|
|
#endif
|
|
|
|
SpinLock currentMappingsLock;
|
|
std::unique_ptr<LocalisedStrings> currentMappings;
|
|
|
|
static int findCloseQuote (const String& text, int startPos)
|
|
{
|
|
juce_wchar lastChar = 0;
|
|
auto t = text.getCharPointer() + startPos;
|
|
|
|
for (;;)
|
|
{
|
|
auto c = t.getAndAdvance();
|
|
|
|
if (c == 0 || (c == '"' && lastChar != '\\'))
|
|
break;
|
|
|
|
lastChar = c;
|
|
++startPos;
|
|
}
|
|
|
|
return startPos;
|
|
}
|
|
|
|
static String unescapeString (const String& s)
|
|
{
|
|
return s.replace ("\\\"", "\"")
|
|
.replace ("\\\'", "\'")
|
|
.replace ("\\t", "\t")
|
|
.replace ("\\r", "\r")
|
|
.replace ("\\n", "\n");
|
|
}
|
|
}
|
|
|
|
void LocalisedStrings::loadFromText (const String& fileContents, bool ignoreCase)
|
|
{
|
|
translations.setIgnoresCase (ignoreCase);
|
|
|
|
StringArray lines;
|
|
lines.addLines (fileContents);
|
|
|
|
for (auto& l : lines)
|
|
{
|
|
auto line = l.trim();
|
|
|
|
if (line.startsWithChar ('"'))
|
|
{
|
|
auto closeQuote = findCloseQuote (line, 1);
|
|
auto originalText = unescapeString (line.substring (1, closeQuote));
|
|
|
|
if (originalText.isNotEmpty())
|
|
{
|
|
auto openingQuote = findCloseQuote (line, closeQuote + 1);
|
|
closeQuote = findCloseQuote (line, openingQuote + 1);
|
|
auto newText = unescapeString (line.substring (openingQuote + 1, closeQuote));
|
|
|
|
if (newText.isNotEmpty())
|
|
translations.set (originalText, newText);
|
|
}
|
|
}
|
|
else if (line.startsWithIgnoreCase ("language:"))
|
|
{
|
|
languageName = line.substring (9).trim();
|
|
}
|
|
else if (line.startsWithIgnoreCase ("countries:"))
|
|
{
|
|
countryCodes.addTokens (line.substring (10).trim(), true);
|
|
countryCodes.trim();
|
|
countryCodes.removeEmptyStrings();
|
|
}
|
|
}
|
|
|
|
translations.minimiseStorageOverheads();
|
|
}
|
|
|
|
void LocalisedStrings::addStrings (const LocalisedStrings& other)
|
|
{
|
|
jassert (languageName == other.languageName);
|
|
jassert (countryCodes == other.countryCodes);
|
|
|
|
translations.addArray (other.translations);
|
|
}
|
|
|
|
void LocalisedStrings::setFallback (LocalisedStrings* f)
|
|
{
|
|
fallback.reset (f);
|
|
}
|
|
|
|
//==============================================================================
|
|
void LocalisedStrings::setCurrentMappings (LocalisedStrings* newTranslations)
|
|
{
|
|
const SpinLock::ScopedLockType sl (currentMappingsLock);
|
|
currentMappings.reset (newTranslations);
|
|
}
|
|
|
|
LocalisedStrings* LocalisedStrings::getCurrentMappings()
|
|
{
|
|
return currentMappings.get();
|
|
}
|
|
|
|
String LocalisedStrings::translateWithCurrentMappings (const String& text) { return juce::translate (text); }
|
|
String LocalisedStrings::translateWithCurrentMappings (const char* text) { return juce::translate (text); }
|
|
|
|
JUCE_API String translate (const String& text) { return juce::translate (text, text); }
|
|
JUCE_API String translate (const char* text) { return juce::translate (String (text)); }
|
|
JUCE_API String translate (CharPointer_UTF8 text) { return juce::translate (String (text)); }
|
|
|
|
JUCE_API String translate (const String& text, const String& resultIfNotFound)
|
|
{
|
|
const SpinLock::ScopedLockType sl (currentMappingsLock);
|
|
|
|
if (auto* mappings = LocalisedStrings::getCurrentMappings())
|
|
return mappings->translate (text, resultIfNotFound);
|
|
|
|
return resultIfNotFound;
|
|
}
|
|
|
|
} // namespace juce
|