[Commits] r2486 - in core/trunk/geoext: lib lib/GeoExt lib/GeoExt/locale tests tests/lib/GeoExt
commits at geoext.org
commits at geoext.org
Tue Nov 23 14:43:48 CET 2010
Author: tschaub
Date: 2010-11-23 14:43:48 +0100 (Tue, 23 Nov 2010)
New Revision: 2486
Added:
core/trunk/geoext/lib/GeoExt/Lang.js
core/trunk/geoext/lib/GeoExt/locale/
core/trunk/geoext/lib/GeoExt/locale/GeoExt-fr.js
core/trunk/geoext/tests/lib/GeoExt/Lang.html
Modified:
core/trunk/geoext/lib/GeoExt.js
core/trunk/geoext/tests/list-tests.html
Log:
Adding simple i18n framework to facilitate localization of applications. Thanks fredj for the French strings. r=ahocevar (closes #352)
Added: core/trunk/geoext/lib/GeoExt/Lang.js
===================================================================
--- core/trunk/geoext/lib/GeoExt/Lang.js (rev 0)
+++ core/trunk/geoext/lib/GeoExt/Lang.js 2010-11-23 13:43:48 UTC (rev 2486)
@@ -0,0 +1,134 @@
+/**
+ * Copyright (c) 2008-2010 The Open Source Geospatial Foundation
+ *
+ * Published under the BSD license.
+ * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
+ * of the license.
+ */
+
+/** api: (define)
+ * module = GeoExt
+ * class = Lang
+ * base_link = `Ext.util.Observable <http://dev.sencha.com/deploy/dev/docs/?class=Ext.util.Observable>`_
+ */
+Ext.namespace("GeoExt");
+
+/** api: constructor
+ * .. class:: Lang
+ *
+ * The GeoExt.Lang singleton is created when the library is loaded.
+ * Include all relevant language files after this file in your build.
+ */
+GeoExt.Lang = new (Ext.extend(Ext.util.Observable, {
+
+ /** api: property[locale]
+ * ``String``
+ * The current language tag. Use :meth:`set` to set the locale. Defaults
+ * to the browser language where available.
+ */
+ locale: navigator.language || navigator.userLanguage,
+
+ /** private: property[dict]
+ * ``Object``
+ * Dictionary of string lookups per language.
+ */
+ dict: null,
+
+ /** private: method[constructor]
+ * Construct the Lang singleton.
+ */
+ constructor: function() {
+ this.addEvents(
+ /** api: event[localize]
+ * Fires when localized strings are set. Listeners will receive a
+ * single ``locale`` event with the language tag.
+ */
+ "localize"
+ );
+ this.dict = {};
+ Ext.util.Observable.constructor.apply(this, arguments);
+ },
+
+ /** api: method[add]
+ * :param locale: ``String`` A language tag that follows the "en-CA"
+ * convention (http://www.ietf.org/rfc/rfc3066.txt).
+ * :param lookup: ``Object`` An object with properties that are dot
+ * delimited names of objects with localizable strings (e.g.
+ * "GeoExt.VectorLegend.prototype"). The values for these properties
+ * are objects that will be used to extend the target objects with
+ * localized strings (e.g. {untitledPrefix: "Untitiled "})
+ *
+ * Add translation strings to the dictionary. This method can be called
+ * multiple times with the same language tag (locale argument) to extend
+ * a single dictionary.
+ */
+ add: function(locale, lookup) {
+ var obj = this.dict[locale];
+ if (!obj) {
+ this.dict[locale] = Ext.apply({}, lookup);
+ } else {
+ for (var key in lookup) {
+ obj[key] = Ext.apply(obj[key] || {}, lookup[key]);
+ }
+ }
+ if (!locale || locale === this.locale) {
+ this.set(locale);
+ } else if (this.locale.indexOf(locale + "-") === 0) {
+ // current locale is regional variation of added strings
+ // call set so newly added strings are used where appropriate
+ this.set(this.locale);
+ }
+ },
+
+ /** api: method[set]
+ * :arg locale: ''String'' Language identifier tag following recommendations
+ * at http://www.ietf.org/rfc/rfc3066.txt.
+ *
+ * Set the language for all GeoExt components. This will use any localized
+ * strings in the dictionary (set with the :meth:`add` method) that
+ * correspond to the complete matching language tag or any "higher order"
+ * tag (e.g. setting "en-CA" will use strings from the "en" dictionary if
+ * matching strings are not found in the "en-CA" dictionary).
+ */
+ set: function(locale) {
+ // compile lookup based on primary and all subtags
+ var tags = locale ? locale.split("-") : [];
+ var id = "";
+ var lookup = {}, parent;
+ for (var i=0, ii=tags.length; i<ii; ++i) {
+ id += (id && "-" || "") + tags[i];
+ if (id in this.dict) {
+ parent = this.dict[id];
+ for (var str in parent) {
+ if (str in lookup) {
+ Ext.apply(lookup[str], parent[str]);
+ } else {
+ lookup[str] = Ext.apply({}, parent[str]);
+ }
+ }
+ }
+ }
+
+ // now extend all objects given by dot delimited names in lookup
+ for (var str in lookup) {
+ var obj = window;
+ var parts = str.split(".");
+ var missing = false;
+ for (var i=0, ii=parts.length; i<ii; ++i) {
+ var name = parts[i];
+ if (name in obj) {
+ obj = obj[name];
+ } else {
+ missing = true;
+ break;
+ }
+ }
+ if (!missing) {
+ Ext.apply(obj, lookup[str]);
+ }
+ }
+ this.locale = locale;
+ this.fireEvent("localize", locale);
+ }
+}))();
+
Added: core/trunk/geoext/lib/GeoExt/locale/GeoExt-fr.js
===================================================================
--- core/trunk/geoext/lib/GeoExt/locale/GeoExt-fr.js (rev 0)
+++ core/trunk/geoext/lib/GeoExt/locale/GeoExt-fr.js 2010-11-23 13:43:48 UTC (rev 2486)
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2008-2010 The Open Source Geospatial Foundation
+ *
+ * Published under the BSD license.
+ * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
+ * of the license.
+ */
+
+/**
+ * @requires GeoExt/Lang.js
+ */
+
+GeoExt.Lang.add("fr", {
+ "GeoExt.tree.LayerContainer.prototype": {
+ text: "Couches"
+ },
+ "GeoExt.tree.BaseLayerContainer.prototype": {
+ text: "Couches de base"
+ },
+ "GeoExt.tree.OverlayLayerContainer.prototype": {
+ text: "Couches additionnelles"
+ }
+});
Modified: core/trunk/geoext/lib/GeoExt.js
===================================================================
--- core/trunk/geoext/lib/GeoExt.js 2010-11-18 12:58:04 UTC (rev 2485)
+++ core/trunk/geoext/lib/GeoExt.js 2010-11-23 13:43:48 UTC (rev 2486)
@@ -119,7 +119,8 @@
"GeoExt/plugins/PrintExtent.js",
"GeoExt/plugins/AttributeForm.js",
"GeoExt/widgets/PrintMapPanel.js",
- "GeoExt/state/PermalinkProvider.js"
+ "GeoExt/state/PermalinkProvider.js",
+ "GeoExt/Lang.js"
);
var agent = navigator.userAgent;
Added: core/trunk/geoext/tests/lib/GeoExt/Lang.html
===================================================================
--- core/trunk/geoext/tests/lib/GeoExt/Lang.html (rev 0)
+++ core/trunk/geoext/tests/lib/GeoExt/Lang.html 2010-11-23 13:43:48 UTC (rev 2486)
@@ -0,0 +1,195 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <script type="text/javascript" src="../../../../ext/adapter/ext/ext-base.js"></script>
+ <script type="text/javascript" src="../../../../ext/ext-all.js"></script>
+ <script type="text/javascript" src="../../../lib/GeoExt/Lang.js"></script>
+ <script type="text/javascript">
+
+ var Test, original = GeoExt.Lang.locale;
+ function setup() {
+ GeoExt.Lang.dict = {};
+ Test = {
+ things: {
+ more: {
+ Class: Ext.extend(Ext.util.Observable, {
+ prop1: "chicken",
+ prop2: "beer"
+ })
+ },
+ Class: Ext.extend(Ext.util.Observable, {
+ prop1: "burger",
+ prop2: "milk"
+ })
+ },
+ data: {
+ foo: "bar"
+ }
+ };
+ }
+ function teardown() {
+ GeoExt.Lang.dict = {};
+ if (original) {
+ GeoExt.Lang.set(original);
+ }
+ Test = undefined;
+ }
+
+ function test_add(t) {
+ t.plan(4);
+ setup();
+
+ GeoExt.Lang.add("en", {
+ "Test.things.more.Class.prototype": {
+ prop1: "potato"
+ },
+ "Test.things.Class.prototype": {
+ prop1: "pizza",
+ prop2: "soda"
+ },
+ "Test.data": {
+ foo: "baz"
+ }
+ });
+
+ t.ok("en" in GeoExt.Lang.dict, "en lookup added");
+ t.eq(GeoExt.Lang.dict.en["Test.data"].foo, "baz", "foo set");
+
+ GeoExt.Lang.add("en", {
+ "Test.data": {
+ bar: "foo"
+ }
+ });
+ t.eq(GeoExt.Lang.dict.en["Test.data"].bar, "foo", "bar set");
+ t.eq(GeoExt.Lang.dict.en["Test.data"].foo, "baz", "foo unchanged");
+
+ teardown();
+ }
+
+ function test_add_more(t) {
+ t.plan(3);
+ setup();
+
+ // assume browser language is regional variation
+ GeoExt.Lang.locale = "xx-YY";
+
+ GeoExt.Lang.add("xx-YY", {
+ "Test.things.Class.prototype": {
+ prop1: "xx-YY"
+ }
+ });
+
+ t.eq(Test.things.Class.prototype.prop1, "xx-YY", "Calling add immediately sets strings when locale matches browser language.");
+
+ GeoExt.Lang.add("xx", {
+ "Test.things.Class.prototype": {
+ prop1: "xx",
+ prop2: "xx"
+ }
+ });
+
+ t.eq(Test.things.Class.prototype.prop1, "xx-YY", "Calling add with more general locale doesn't override regional specific strings.");
+ t.eq(Test.things.Class.prototype.prop2, "xx", "Calling add with more general locale than browser language sets strings not previously set.");
+
+ teardown();
+ }
+
+ function test_set(t) {
+ t.plan(12);
+ setup();
+
+ GeoExt.Lang.add("en", {
+ "Test.things.more.Class.prototype": {
+ prop1: "potato"
+ },
+ "Test.things.Class.prototype": {
+ prop1: "pizza",
+ prop2: "soda"
+ },
+ "Test.data": {
+ foo: "baz"
+ }
+ });
+
+ GeoExt.Lang.add("xx-YY", {
+ "Test.data": {
+ foo: "bar xx-YY"
+ }
+ })
+
+ GeoExt.Lang.add("xx", {
+ "Test.things.more.Class.prototype": {
+ prop1: "steak"
+ },
+ "Test.things.Class.prototype": {
+ prop1: "pasta",
+ prop2: "water"
+ },
+ "Test.data": {
+ foo: "bar xx"
+ }
+ });
+
+ GeoExt.Lang.set("en");
+ t.eq(GeoExt.Lang.locale, "en", "locale set to en");
+
+ t.eq(Test.things.more.Class.prototype.prop1, "potato", "[en] potato set");
+ t.eq(Test.things.more.Class.prototype.prop2, "beer", "[en] beer unmolested");
+ t.eq(Test.things.Class.prototype.prop1, "pizza", "[en] pizza set");
+ t.eq(Test.things.Class.prototype.prop2, "soda", "[en] soda set");
+ t.eq(Test.data.foo, "baz", "[en] baz set");
+
+ GeoExt.Lang.set("xx-YY");
+ t.eq(GeoExt.Lang.locale, "xx-YY", "locale set to xx-YY");
+
+ t.eq(Test.things.more.Class.prototype.prop1, "steak", "[xx-YY] steak set");
+ t.eq(Test.things.more.Class.prototype.prop2, "beer", "[xx-YY] beer unmolested");
+ t.eq(Test.things.Class.prototype.prop1, "pasta", "[xx-YY] pasta set");
+ t.eq(Test.things.Class.prototype.prop2, "water", "[xx-YY] water set");
+ t.eq(Test.data.foo, "bar xx-YY", "[xx-YY] baz xx-YY set");
+
+ teardown();
+ }
+
+ function test_browser_language(t) {
+ setup();
+
+ var locale = navigator.language || navigator.userLanguage;
+ if (locale) {
+
+ t.plan(5)
+ t.eq(GeoExt.Lang.locale, locale, "Locale set to browser language when available.");
+
+ GeoExt.Lang.add("boguslang", {
+ "Test.data": {
+ foo: "bogus"
+ }
+ });
+
+ t.ok(GeoExt.Lang.locale !== "boguslang", "Adding localized strings doesn't change locale if browser language is detected");
+ t.ok(Test.data.foo !== "bogus", "Default values not changed when localized strings are added for non-browser language");
+
+ GeoExt.Lang.add(locale, {
+ "Test.data": {
+ foo: "localized"
+ }
+ });
+
+ t.eq(Test.data.foo, "localized", "Adding localized strings for browser language sets values on target objects");
+
+ GeoExt.Lang.set("boguslang");
+ t.eq(Test.data.foo, "bogus", "Call GeoExt.Lang.set to override browser default language");
+
+ } else {
+ t.plan(1);
+ t.debug("No browser language detected.")
+ t.ok(true, "No browser language detected, nothing to test");
+ }
+
+ teardown();
+ }
+
+ </script>
+ </head>
+ <body></body>
+</html>
Modified: core/trunk/geoext/tests/list-tests.html
===================================================================
--- core/trunk/geoext/tests/list-tests.html 2010-11-18 12:58:04 UTC (rev 2485)
+++ core/trunk/geoext/tests/list-tests.html 2010-11-23 13:43:48 UTC (rev 2486)
@@ -16,6 +16,7 @@
<li>lib/GeoExt/data/WMSCapabilitiesReader.html</li>
<li>lib/GeoExt/data/WMSDescribeLayerReader.html</li>
<li>lib/GeoExt/data/WMCReader.html</li>
+ <li>lib/GeoExt/Lang.html</li>
<li>lib/GeoExt/plugins/PrintPageField.html</li>
<li>lib/GeoExt/plugins/PrintProviderField.html</li>
<li>lib/GeoExt/plugins/PrintExtent.html</li>
More information about the Commits
mailing list