diff options
Diffstat (limited to 'src/3rdparty/v8/src/extensions/experimental/i18n-extension.cc')
-rw-r--r-- | src/3rdparty/v8/src/extensions/experimental/i18n-extension.cc | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/src/3rdparty/v8/src/extensions/experimental/i18n-extension.cc b/src/3rdparty/v8/src/extensions/experimental/i18n-extension.cc new file mode 100644 index 0000000..f14fd9e --- /dev/null +++ b/src/3rdparty/v8/src/extensions/experimental/i18n-extension.cc @@ -0,0 +1,284 @@ +// Copyright 2010 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "i18n-extension.h" + +#include <algorithm> +#include <string> + +#include "break-iterator.h" +#include "unicode/locid.h" +#include "unicode/uloc.h" + +namespace v8 { +namespace internal { + +I18NExtension* I18NExtension::extension_ = NULL; + +// TODO(cira): maybe move JS code to a .js file and generata cc files from it? +// TODO(cira): Remove v8 prefix from v8Locale once we have stable API. +const char* const I18NExtension::kSource = + "v8Locale = function(optLocale) {" + " native function NativeJSLocale();" + " var properties = NativeJSLocale(optLocale);" + " this.locale = properties.locale;" + " this.language = properties.language;" + " this.script = properties.script;" + " this.region = properties.region;" + "};" + "v8Locale.availableLocales = function() {" + " native function NativeJSAvailableLocales();" + " return NativeJSAvailableLocales();" + "};" + "v8Locale.prototype.maximizedLocale = function() {" + " native function NativeJSMaximizedLocale();" + " return new v8Locale(NativeJSMaximizedLocale(this.locale));" + "};" + "v8Locale.prototype.minimizedLocale = function() {" + " native function NativeJSMinimizedLocale();" + " return new v8Locale(NativeJSMinimizedLocale(this.locale));" + "};" + "v8Locale.prototype.displayLocale_ = function(displayLocale) {" + " var result = this.locale;" + " if (displayLocale !== undefined) {" + " result = displayLocale.locale;" + " }" + " return result;" + "};" + "v8Locale.prototype.displayLanguage = function(optDisplayLocale) {" + " var displayLocale = this.displayLocale_(optDisplayLocale);" + " native function NativeJSDisplayLanguage();" + " return NativeJSDisplayLanguage(this.locale, displayLocale);" + "};" + "v8Locale.prototype.displayScript = function(optDisplayLocale) {" + " var displayLocale = this.displayLocale_(optDisplayLocale);" + " native function NativeJSDisplayScript();" + " return NativeJSDisplayScript(this.locale, displayLocale);" + "};" + "v8Locale.prototype.displayRegion = function(optDisplayLocale) {" + " var displayLocale = this.displayLocale_(optDisplayLocale);" + " native function NativeJSDisplayRegion();" + " return NativeJSDisplayRegion(this.locale, displayLocale);" + "};" + "v8Locale.prototype.displayName = function(optDisplayLocale) {" + " var displayLocale = this.displayLocale_(optDisplayLocale);" + " native function NativeJSDisplayName();" + " return NativeJSDisplayName(this.locale, displayLocale);" + "};" + "v8Locale.v8BreakIterator = function(locale, type) {" + " native function NativeJSBreakIterator();" + " var iterator = NativeJSBreakIterator(locale, type);" + " iterator.type = type;" + " return iterator;" + "};" + "v8Locale.v8BreakIterator.BreakType = {" + " 'unknown': -1," + " 'none': 0," + " 'number': 100," + " 'word': 200," + " 'kana': 300," + " 'ideo': 400" + "};" + "v8Locale.prototype.v8CreateBreakIterator = function(type) {" + " return new v8Locale.v8BreakIterator(this.locale, type);" + "};"; + +v8::Handle<v8::FunctionTemplate> I18NExtension::GetNativeFunction( + v8::Handle<v8::String> name) { + if (name->Equals(v8::String::New("NativeJSLocale"))) { + return v8::FunctionTemplate::New(JSLocale); + } else if (name->Equals(v8::String::New("NativeJSAvailableLocales"))) { + return v8::FunctionTemplate::New(JSAvailableLocales); + } else if (name->Equals(v8::String::New("NativeJSMaximizedLocale"))) { + return v8::FunctionTemplate::New(JSMaximizedLocale); + } else if (name->Equals(v8::String::New("NativeJSMinimizedLocale"))) { + return v8::FunctionTemplate::New(JSMinimizedLocale); + } else if (name->Equals(v8::String::New("NativeJSDisplayLanguage"))) { + return v8::FunctionTemplate::New(JSDisplayLanguage); + } else if (name->Equals(v8::String::New("NativeJSDisplayScript"))) { + return v8::FunctionTemplate::New(JSDisplayScript); + } else if (name->Equals(v8::String::New("NativeJSDisplayRegion"))) { + return v8::FunctionTemplate::New(JSDisplayRegion); + } else if (name->Equals(v8::String::New("NativeJSDisplayName"))) { + return v8::FunctionTemplate::New(JSDisplayName); + } else if (name->Equals(v8::String::New("NativeJSBreakIterator"))) { + return v8::FunctionTemplate::New(BreakIterator::JSBreakIterator); + } + + return v8::Handle<v8::FunctionTemplate>(); +} + +v8::Handle<v8::Value> I18NExtension::JSLocale(const v8::Arguments& args) { + // TODO(cira): Fetch browser locale. Accept en-US as good default for now. + // We could possibly pass browser locale as a parameter in the constructor. + std::string locale_name("en-US"); + if (args.Length() == 1 && args[0]->IsString()) { + locale_name = *v8::String::Utf8Value(args[0]->ToString()); + } + + v8::Local<v8::Object> locale = v8::Object::New(); + locale->Set(v8::String::New("locale"), v8::String::New(locale_name.c_str())); + + icu::Locale icu_locale(locale_name.c_str()); + + const char* language = icu_locale.getLanguage(); + locale->Set(v8::String::New("language"), v8::String::New(language)); + + const char* script = icu_locale.getScript(); + if (strlen(script)) { + locale->Set(v8::String::New("script"), v8::String::New(script)); + } + + const char* region = icu_locale.getCountry(); + if (strlen(region)) { + locale->Set(v8::String::New("region"), v8::String::New(region)); + } + + return locale; +} + +// TODO(cira): Filter out locales that Chrome doesn't support. +v8::Handle<v8::Value> I18NExtension::JSAvailableLocales( + const v8::Arguments& args) { + v8::Local<v8::Array> all_locales = v8::Array::New(); + + int count = 0; + const icu::Locale* icu_locales = icu::Locale::getAvailableLocales(count); + for (int i = 0; i < count; ++i) { + all_locales->Set(i, v8::String::New(icu_locales[i].getName())); + } + + return all_locales; +} + +// Use - as tag separator, not _ that ICU uses. +static std::string NormalizeLocale(const std::string& locale) { + std::string result(locale); + // TODO(cira): remove STL dependency. + std::replace(result.begin(), result.end(), '_', '-'); + return result; +} + +v8::Handle<v8::Value> I18NExtension::JSMaximizedLocale( + const v8::Arguments& args) { + if (!args.Length() || !args[0]->IsString()) { + return v8::Undefined(); + } + + UErrorCode status = U_ZERO_ERROR; + std::string locale_name = *v8::String::Utf8Value(args[0]->ToString()); + char max_locale[ULOC_FULLNAME_CAPACITY]; + uloc_addLikelySubtags(locale_name.c_str(), max_locale, + sizeof(max_locale), &status); + if (U_FAILURE(status)) { + return v8::Undefined(); + } + + return v8::String::New(NormalizeLocale(max_locale).c_str()); +} + +v8::Handle<v8::Value> I18NExtension::JSMinimizedLocale( + const v8::Arguments& args) { + if (!args.Length() || !args[0]->IsString()) { + return v8::Undefined(); + } + + UErrorCode status = U_ZERO_ERROR; + std::string locale_name = *v8::String::Utf8Value(args[0]->ToString()); + char min_locale[ULOC_FULLNAME_CAPACITY]; + uloc_minimizeSubtags(locale_name.c_str(), min_locale, + sizeof(min_locale), &status); + if (U_FAILURE(status)) { + return v8::Undefined(); + } + + return v8::String::New(NormalizeLocale(min_locale).c_str()); +} + +// Common code for JSDisplayXXX methods. +static v8::Handle<v8::Value> GetDisplayItem(const v8::Arguments& args, + const std::string& item) { + if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsString()) { + return v8::Undefined(); + } + + std::string base_locale = *v8::String::Utf8Value(args[0]->ToString()); + icu::Locale icu_locale(base_locale.c_str()); + icu::Locale display_locale = + icu::Locale(*v8::String::Utf8Value(args[1]->ToString())); + icu::UnicodeString result; + if (item == "language") { + icu_locale.getDisplayLanguage(display_locale, result); + } else if (item == "script") { + icu_locale.getDisplayScript(display_locale, result); + } else if (item == "region") { + icu_locale.getDisplayCountry(display_locale, result); + } else if (item == "name") { + icu_locale.getDisplayName(display_locale, result); + } else { + return v8::Undefined(); + } + + if (result.length()) { + return v8::String::New( + reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length()); + } + + return v8::Undefined(); +} + +v8::Handle<v8::Value> I18NExtension::JSDisplayLanguage( + const v8::Arguments& args) { + return GetDisplayItem(args, "language"); +} + +v8::Handle<v8::Value> I18NExtension::JSDisplayScript( + const v8::Arguments& args) { + return GetDisplayItem(args, "script"); +} + +v8::Handle<v8::Value> I18NExtension::JSDisplayRegion( + const v8::Arguments& args) { + return GetDisplayItem(args, "region"); +} + +v8::Handle<v8::Value> I18NExtension::JSDisplayName(const v8::Arguments& args) { + return GetDisplayItem(args, "name"); +} + +I18NExtension* I18NExtension::get() { + if (!extension_) { + extension_ = new I18NExtension(); + } + return extension_; +} + +void I18NExtension::Register() { + static v8::DeclareExtension i18n_extension_declaration(I18NExtension::get()); +} + +} } // namespace v8::internal |