Adding angular-gettext to xstatic package
Angular-gettext provides simple translation support for AngularJS. We plan on using this in Horizon. This patch creates a stackforge repo for it. Change-Id: I74e9b286e16b4a172488510a1ed70421c158e23b
This commit is contained in:
parent
2ab6ccd694
commit
86c16c5941
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
*.pyc
|
||||
*.sw?
|
||||
*.sqlite3
|
||||
.DS_STORE
|
||||
*.egg-info
|
||||
.venv
|
||||
.tox
|
||||
build
|
||||
dist
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (C) 2013-2015 by Ruben Vermeersch <ruben@rocketeer.be>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
8
MANIFEST.in
Normal file
8
MANIFEST.in
Normal file
@ -0,0 +1,8 @@
|
||||
include README.txt
|
||||
recursive-include xstatic/pkg/angular_gettext *
|
||||
|
||||
global-exclude *.pyc
|
||||
global-exclude *.pyo
|
||||
global-exclude *.orig
|
||||
global-exclude *.rej
|
||||
|
13
README.txt
Normal file
13
README.txt
Normal file
@ -0,0 +1,13 @@
|
||||
XStatic-Angular-Gettext
|
||||
--------------
|
||||
|
||||
Angular-Gettext javascript library packaged for setuptools (easy_install) / pip.
|
||||
|
||||
This package is intended to be used by **any** project that needs these files.
|
||||
|
||||
It intentionally does **not** provide any extra code except some metadata
|
||||
**nor** has any extra requirements. You MAY use some minimal support code from
|
||||
the XStatic base package, if you like.
|
||||
|
||||
You can find more info about the xstatic packaging way in the package `XStatic`.
|
||||
|
27
setup.py
Normal file
27
setup.py
Normal file
@ -0,0 +1,27 @@
|
||||
from xstatic.pkg import angular_gettext as xs
|
||||
|
||||
# The README.txt file should be written in reST so that PyPI can use
|
||||
# it to generate your project's PyPI page.
|
||||
long_description = open('README.txt').read()
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name=xs.PACKAGE_NAME,
|
||||
version=xs.PACKAGE_VERSION,
|
||||
description=xs.DESCRIPTION,
|
||||
long_description=long_description,
|
||||
classifiers=xs.CLASSIFIERS,
|
||||
keywords=xs.KEYWORDS,
|
||||
maintainer=xs.MAINTAINER,
|
||||
maintainer_email=xs.MAINTAINER_EMAIL,
|
||||
license=xs.LICENSE,
|
||||
url=xs.HOMEPAGE,
|
||||
platforms=xs.PLATFORMS,
|
||||
packages=find_packages(),
|
||||
namespace_packages=['xstatic', 'xstatic.pkg', ],
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
install_requires=[], # nothing! :)
|
||||
# if you like, you MAY use the 'XStatic' package.
|
||||
)
|
10
tox.ini
Normal file
10
tox.ini
Normal file
@ -0,0 +1,10 @@
|
||||
[tox]
|
||||
minversion = 1.6
|
||||
skipsdist = True
|
||||
envlist = py27,py33,py34
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
||||
[tox:jenkins]
|
||||
downloadcache = ~/cache/pip
|
1
xstatic/__init__.py
Normal file
1
xstatic/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
1
xstatic/pkg/__init__.py
Normal file
1
xstatic/pkg/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
50
xstatic/pkg/angular_gettext/__init__.py
Normal file
50
xstatic/pkg/angular_gettext/__init__.py
Normal file
@ -0,0 +1,50 @@
|
||||
"""
|
||||
XStatic resource package
|
||||
|
||||
See package 'XStatic' for documentation and basic tools.
|
||||
"""
|
||||
|
||||
DISPLAY_NAME = 'Angular-Gettext' # official name, upper/lowercase allowed, no spaces
|
||||
PACKAGE_NAME = 'XStatic-%s' % DISPLAY_NAME # name used for PyPi
|
||||
|
||||
NAME = __name__.split('.')[-1] # package name (e.g. 'foo' or 'foo_bar')
|
||||
# please use a all-lowercase valid python
|
||||
# package name
|
||||
|
||||
VERSION = '2.1.0' # version of the packaged files, please use the upstream
|
||||
# version number
|
||||
BUILD = '1' # our package build number, so we can release new builds
|
||||
# with fixes for xstatic stuff.
|
||||
PACKAGE_VERSION = VERSION + '.' + BUILD # version used for PyPi
|
||||
|
||||
DESCRIPTION = "%s %s (XStatic packaging standard)" % (DISPLAY_NAME, VERSION)
|
||||
|
||||
PLATFORMS = 'any'
|
||||
CLASSIFIERS = []
|
||||
KEYWORDS = '%s xstatic' % NAME
|
||||
|
||||
# XStatic-* package maintainer:
|
||||
MAINTAINER = 'Thai Tran'
|
||||
MAINTAINER_EMAIL = 'tqtran@us.ibm.com'
|
||||
|
||||
# this refers to the project homepage of the stuff we packaged:
|
||||
HOMEPAGE = 'https://angular-gettext.rocketeer.be/'
|
||||
|
||||
# this refers to all files:
|
||||
LICENSE = '(same as %s)' % DISPLAY_NAME
|
||||
|
||||
from os.path import join, dirname
|
||||
BASE_DIR = join(dirname(__file__), 'data')
|
||||
# linux package maintainers just can point to their file locations like this:
|
||||
#BASE_DIR = '/usr/share/javascript/jquery'
|
||||
|
||||
LOCATIONS = {
|
||||
# CDN locations (if no public CDN exists, use an empty dict)
|
||||
# if value is a string, it is a base location, just append relative
|
||||
# path/filename. if value is a dict, do another lookup using the
|
||||
# relative path/filename you want.
|
||||
# your relative path/filenames should usually be without version
|
||||
# information, because either the base dir/url is exactly for this
|
||||
# version or the mapping will care for accessing this version.
|
||||
}
|
||||
|
352
xstatic/pkg/angular_gettext/data/angular-gettext.js
vendored
Normal file
352
xstatic/pkg/angular_gettext/data/angular-gettext.js
vendored
Normal file
@ -0,0 +1,352 @@
|
||||
angular.module('gettext', []);
|
||||
|
||||
angular.module('gettext').constant('gettext', function (str) {
|
||||
/*
|
||||
* Does nothing, simply returns the input string.
|
||||
*
|
||||
* This function serves as a marker for `grunt-angular-gettext` to know that
|
||||
* this string should be extracted for translations.
|
||||
*/
|
||||
return str;
|
||||
});
|
||||
|
||||
angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "$http", "$cacheFactory", "$interpolate", "$rootScope", function (gettextPlurals, $http, $cacheFactory, $interpolate, $rootScope) {
|
||||
var catalog;
|
||||
var noContext = '$$noContext';
|
||||
|
||||
// IE8 returns UPPER CASE tags, even though the source is lower case.
|
||||
// This can causes the (key) string in the DOM to have a different case to
|
||||
// the string in the `po` files.
|
||||
// IE9, IE10 and IE11 reorders the attributes of tags.
|
||||
var test = '<span id="test" title="test" class="tested">test</span>';
|
||||
var isHTMLModified = (angular.element('<span>' + test + '</span>').html() !== test);
|
||||
|
||||
var prefixDebug = function (string) {
|
||||
if (catalog.debug && catalog.currentLanguage !== catalog.baseLanguage) {
|
||||
return catalog.debugPrefix + string;
|
||||
} else {
|
||||
return string;
|
||||
}
|
||||
};
|
||||
|
||||
var addTranslatedMarkers = function (string) {
|
||||
if (catalog.showTranslatedMarkers) {
|
||||
return catalog.translatedMarkerPrefix + string + catalog.translatedMarkerSuffix;
|
||||
} else {
|
||||
return string;
|
||||
}
|
||||
};
|
||||
|
||||
function broadcastUpdated() {
|
||||
$rootScope.$broadcast('gettextLanguageChanged');
|
||||
}
|
||||
|
||||
catalog = {
|
||||
debug: false,
|
||||
debugPrefix: '[MISSING]: ',
|
||||
showTranslatedMarkers: false,
|
||||
translatedMarkerPrefix: '[',
|
||||
translatedMarkerSuffix: ']',
|
||||
strings: {},
|
||||
baseLanguage: 'en',
|
||||
currentLanguage: 'en',
|
||||
cache: $cacheFactory('strings'),
|
||||
|
||||
setCurrentLanguage: function (lang) {
|
||||
this.currentLanguage = lang;
|
||||
broadcastUpdated();
|
||||
},
|
||||
|
||||
getCurrentLanguage: function () {
|
||||
return this.currentLanguage;
|
||||
},
|
||||
|
||||
setStrings: function (language, strings) {
|
||||
if (!this.strings[language]) {
|
||||
this.strings[language] = {};
|
||||
}
|
||||
|
||||
for (var key in strings) {
|
||||
var val = strings[key];
|
||||
|
||||
if (isHTMLModified) {
|
||||
// Use the DOM engine to render any HTML in the key (#131).
|
||||
key = angular.element('<span>' + key + '</span>').html();
|
||||
}
|
||||
|
||||
if (angular.isString(val) || angular.isArray(val)) {
|
||||
// No context, wrap it in $$noContext.
|
||||
var obj = {};
|
||||
obj[noContext] = val;
|
||||
val = obj;
|
||||
}
|
||||
|
||||
// Expand single strings for each context.
|
||||
for (var context in val) {
|
||||
var str = val[context];
|
||||
val[context] = angular.isArray(str) ? str : [str];
|
||||
}
|
||||
this.strings[language][key] = val;
|
||||
}
|
||||
|
||||
broadcastUpdated();
|
||||
},
|
||||
|
||||
getStringForm: function (string, n, context) {
|
||||
var stringTable = this.strings[this.currentLanguage] || {};
|
||||
var contexts = stringTable[string] || {};
|
||||
var plurals = contexts[context || noContext] || [];
|
||||
return plurals[n];
|
||||
},
|
||||
|
||||
getString: function (string, scope, context) {
|
||||
string = this.getStringForm(string, 0, context) || prefixDebug(string);
|
||||
string = scope ? $interpolate(string)(scope) : string;
|
||||
return addTranslatedMarkers(string);
|
||||
},
|
||||
|
||||
getPlural: function (n, string, stringPlural, scope, context) {
|
||||
var form = gettextPlurals(this.currentLanguage, n);
|
||||
string = this.getStringForm(string, form, context) || prefixDebug(n === 1 ? string : stringPlural);
|
||||
if (scope) {
|
||||
scope.$count = n;
|
||||
string = $interpolate(string)(scope);
|
||||
}
|
||||
return addTranslatedMarkers(string);
|
||||
},
|
||||
|
||||
loadRemote: function (url) {
|
||||
return $http({
|
||||
method: 'GET',
|
||||
url: url,
|
||||
cache: catalog.cache
|
||||
}).success(function (data) {
|
||||
for (var lang in data) {
|
||||
catalog.setStrings(lang, data[lang]);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return catalog;
|
||||
}]);
|
||||
|
||||
angular.module('gettext').directive('translate', ["gettextCatalog", "$parse", "$animate", "$compile", "$window", function (gettextCatalog, $parse, $animate, $compile, $window) {
|
||||
// Trim polyfill for old browsers (instead of jQuery)
|
||||
// Based on AngularJS-v1.2.2 (angular.js#620)
|
||||
var trim = (function () {
|
||||
if (!String.prototype.trim) {
|
||||
return function (value) {
|
||||
return (typeof value === 'string') ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value;
|
||||
};
|
||||
}
|
||||
return function (value) {
|
||||
return (typeof value === 'string') ? value.trim() : value;
|
||||
};
|
||||
})();
|
||||
|
||||
function assert(condition, missing, found) {
|
||||
if (!condition) {
|
||||
throw new Error('You should add a ' + missing + ' attribute whenever you add a ' + found + ' attribute.');
|
||||
}
|
||||
}
|
||||
|
||||
var msie = parseInt((/msie (\d+)/.exec(angular.lowercase($window.navigator.userAgent)) || [])[1], 10);
|
||||
|
||||
return {
|
||||
restrict: 'AE',
|
||||
terminal: true,
|
||||
compile: function compile(element, attrs) {
|
||||
// Validate attributes
|
||||
assert(!attrs.translatePlural || attrs.translateN, 'translate-n', 'translate-plural');
|
||||
assert(!attrs.translateN || attrs.translatePlural, 'translate-plural', 'translate-n');
|
||||
|
||||
var msgid = trim(element.html());
|
||||
var translatePlural = attrs.translatePlural;
|
||||
var translateContext = attrs.translateContext;
|
||||
|
||||
if (msie <= 8) {
|
||||
// Workaround fix relating to angular adding a comment node to
|
||||
// anchors. angular/angular.js/#1949 / angular/angular.js/#2013
|
||||
if (msgid.slice(-13) === '<!--IE fix-->') {
|
||||
msgid = msgid.slice(0, -13);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
post: function (scope, element, attrs) {
|
||||
var countFn = $parse(attrs.translateN);
|
||||
var pluralScope = null;
|
||||
var linking = true;
|
||||
|
||||
function update() {
|
||||
// Fetch correct translated string.
|
||||
var translated;
|
||||
if (translatePlural) {
|
||||
scope = pluralScope || (pluralScope = scope.$new());
|
||||
scope.$count = countFn(scope);
|
||||
translated = gettextCatalog.getPlural(scope.$count, msgid, translatePlural, null, translateContext);
|
||||
} else {
|
||||
translated = gettextCatalog.getString(msgid, null, translateContext);
|
||||
}
|
||||
|
||||
var oldContents = element.contents();
|
||||
|
||||
if (oldContents.length === 0){
|
||||
return;
|
||||
}
|
||||
|
||||
// Avoid redundant swaps
|
||||
if (translated === trim(oldContents.html())){
|
||||
// Take care of unlinked content
|
||||
if (linking){
|
||||
$compile(oldContents)(scope);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Swap in the translation
|
||||
var newWrapper = angular.element('<span>' + translated + '</span>');
|
||||
$compile(newWrapper.contents())(scope);
|
||||
var newContents = newWrapper.contents();
|
||||
|
||||
$animate.enter(newContents, element);
|
||||
$animate.leave(oldContents);
|
||||
}
|
||||
|
||||
if (attrs.translateN) {
|
||||
scope.$watch(attrs.translateN, update);
|
||||
}
|
||||
|
||||
scope.$on('gettextLanguageChanged', update);
|
||||
|
||||
update();
|
||||
linking = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
angular.module('gettext').filter('translate', ["gettextCatalog", function (gettextCatalog) {
|
||||
function filter(input, context) {
|
||||
return gettextCatalog.getString(input, null, context);
|
||||
}
|
||||
filter.$stateful = true;
|
||||
return filter;
|
||||
}]);
|
||||
|
||||
// Do not edit this file, it is autogenerated using genplurals.py!
|
||||
angular.module("gettext").factory("gettextPlurals", function () {
|
||||
return function (langCode, n) {
|
||||
switch (langCode) {
|
||||
case "ay": // Aymará
|
||||
case "bo": // Tibetan
|
||||
case "cgg": // Chiga
|
||||
case "dz": // Dzongkha
|
||||
case "fa": // Persian
|
||||
case "id": // Indonesian
|
||||
case "ja": // Japanese
|
||||
case "jbo": // Lojban
|
||||
case "ka": // Georgian
|
||||
case "kk": // Kazakh
|
||||
case "km": // Khmer
|
||||
case "ko": // Korean
|
||||
case "ky": // Kyrgyz
|
||||
case "lo": // Lao
|
||||
case "ms": // Malay
|
||||
case "my": // Burmese
|
||||
case "sah": // Yakut
|
||||
case "su": // Sundanese
|
||||
case "th": // Thai
|
||||
case "tt": // Tatar
|
||||
case "ug": // Uyghur
|
||||
case "vi": // Vietnamese
|
||||
case "wo": // Wolof
|
||||
case "zh": // Chinese
|
||||
// 1 form
|
||||
return 0;
|
||||
case "is": // Icelandic
|
||||
// 2 forms
|
||||
return (n%10!=1 || n%100==11) ? 1 : 0;
|
||||
case "jv": // Javanese
|
||||
// 2 forms
|
||||
return n!=0 ? 1 : 0;
|
||||
case "mk": // Macedonian
|
||||
// 2 forms
|
||||
return n==1 || n%10==1 ? 0 : 1;
|
||||
case "ach": // Acholi
|
||||
case "ak": // Akan
|
||||
case "am": // Amharic
|
||||
case "arn": // Mapudungun
|
||||
case "br": // Breton
|
||||
case "fil": // Filipino
|
||||
case "fr": // French
|
||||
case "gun": // Gun
|
||||
case "ln": // Lingala
|
||||
case "mfe": // Mauritian Creole
|
||||
case "mg": // Malagasy
|
||||
case "mi": // Maori
|
||||
case "oc": // Occitan
|
||||
case "pt_BR": // Brazilian Portuguese
|
||||
case "tg": // Tajik
|
||||
case "ti": // Tigrinya
|
||||
case "tr": // Turkish
|
||||
case "uz": // Uzbek
|
||||
case "wa": // Walloon
|
||||
case "zh": // Chinese
|
||||
// 2 forms
|
||||
return n>1 ? 1 : 0;
|
||||
case "lv": // Latvian
|
||||
// 3 forms
|
||||
return (n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);
|
||||
case "lt": // Lithuanian
|
||||
// 3 forms
|
||||
return (n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);
|
||||
case "be": // Belarusian
|
||||
case "bs": // Bosnian
|
||||
case "hr": // Croatian
|
||||
case "ru": // Russian
|
||||
case "sr": // Serbian
|
||||
case "uk": // Ukrainian
|
||||
// 3 forms
|
||||
return (n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);
|
||||
case "mnk": // Mandinka
|
||||
// 3 forms
|
||||
return (n==0 ? 0 : n==1 ? 1 : 2);
|
||||
case "ro": // Romanian
|
||||
// 3 forms
|
||||
return (n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2);
|
||||
case "pl": // Polish
|
||||
// 3 forms
|
||||
return (n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);
|
||||
case "cs": // Czech
|
||||
case "sk": // Slovak
|
||||
// 3 forms
|
||||
return (n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;
|
||||
case "sl": // Slovenian
|
||||
// 4 forms
|
||||
return (n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0);
|
||||
case "mt": // Maltese
|
||||
// 4 forms
|
||||
return (n==1 ? 0 : n==0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3);
|
||||
case "gd": // Scottish Gaelic
|
||||
// 4 forms
|
||||
return (n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3;
|
||||
case "cy": // Welsh
|
||||
// 4 forms
|
||||
return (n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;
|
||||
case "kw": // Cornish
|
||||
// 4 forms
|
||||
return (n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : 3;
|
||||
case "ga": // Irish
|
||||
// 5 forms
|
||||
return n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4;
|
||||
case "ar": // Arabic
|
||||
// 6 forms
|
||||
return (n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5);
|
||||
default: // Everything else
|
||||
return n != 1 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user