diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..019922a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 Angel Todorov
+
+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.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3be57dc
--- /dev/null
+++ b/README.md
@@ -0,0 +1,57 @@
+# bower-angularjs-localization
+
+This repo is for distribution on `bower`. The source for this module is in the
+[main AngularJS Localization repo](https://github.com/angel1st/angularjs-localization).
+Please file issues and pull requests against that repo.
+
+## Install
+
+Install with `bower`:
+
+```shell
+bower install angular-localization
+```
+
+Add a `
+
+
+
+```
+
+Inject the dependency into your application module
+
+```js
+angular.module('myApp', ['ngLocalize']);
+```
+
+## Documentation
+
+Documentation is available on the
+[main AngularJS Localization repo](https://github.com/angel1st/angularjs-localization).
+
+## License
+
+The MIT License (MIT)
+
+Copyright (c) 2018 Angel Todorov
+
+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.
diff --git a/angularjs-localization.js b/angularjs-localization.js
new file mode 100644
index 0000000..0d668ea
--- /dev/null
+++ b/angularjs-localization.js
@@ -0,0 +1,416 @@
+/**
+ * angular-localization :: v1.2.1 :: 2015-04-17
+ * web: https://github.com/doshprompt/angular-localization
+ *
+ * Copyright (c) 2015 | Rahul Doshi
+ * License: MIT
+ */
+;(function (angular, window, document, undefined) {
+ 'use strict';
+angular.module('ngLocalize.Config', [])
+ .value('localeConf', {
+ basePath: 'languages',
+ defaultLocale: 'en-US',
+ sharedDictionary: 'common',
+ fileExtension: '.lang.json',
+ persistSelection: true,
+ cookieName: 'COOKIE_LOCALE_LANG',
+ observableAttrs: new RegExp('^data-(?!ng-|i18n)'),
+ delimiter: '::'
+ });
+angular.module('ngLocalize.Events', [])
+ .constant('localeEvents', {
+ resourceUpdates: 'ngLocalizeResourcesUpdated',
+ localeChanges: 'ngLocalizeLocaleChanged'
+ });
+angular.module('ngLocalize', ['ngSanitize', 'ngLocalize.Config', 'ngLocalize.Events', 'ngLocalize.InstalledLanguages'])
+ .service('locale', ['$injector', '$http', '$q', '$log', '$rootScope', '$window', 'localeConf', 'localeEvents', 'localeSupported', 'localeFallbacks',
+ function ($injector, $http, $q, $log, $rootScope, $window, localeConf, localeEvents, localeSupported, localeFallbacks) {
+ var TOKEN_REGEX = new RegExp('^[\\w\\.-]+\\.[\\w\\s\\.-]+\\w(:.*)?$'),
+ currentLocale,
+ deferrences,
+ bundles,
+ cookieStore;
+
+ if (localeConf.persistSelection && $injector.has('$cookieStore')) {
+ cookieStore = $injector.get('$cookieStore');
+ }
+
+ function isToken(str) {
+ return (str && str.length && TOKEN_REGEX.test(str));
+ }
+
+ function getPath(tok) {
+ var path = tok ? tok.split('.') : '',
+ result = '';
+
+ if (path.length > 1) {
+ result = path.slice(0, -1).join('.');
+ }
+
+ return result;
+ }
+
+ function getKey(tok) {
+ var path = tok ? tok.split('.') : [],
+ result = '';
+
+ if (path.length) {
+ result = path[path.length - 1];
+ }
+
+ return result;
+ }
+
+ function getBundle(tok) {
+ var result = null,
+ path = tok ? tok.split('.') : [],
+ i;
+
+ if (path.length > 1) {
+ result = bundles;
+
+ for (i = 0; i < path.length - 1; i++) {
+ if (result[path[i]]) {
+ result = result[path[i]];
+ } else {
+ result = null;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ function loadBundle(token) {
+ var path = token ? token.split('.') : '',
+ root = bundles,
+ url = localeConf.basePath + '/' + currentLocale,
+ i;
+
+ if (path.length > 1) {
+ for (i = 0; i < path.length - 1; i++) {
+ if (!root[path[i]]) {
+ root[path[i]] = {};
+ }
+ root = root[path[i]];
+ url += "/" + path[i];
+ }
+
+ if (!root._loading) {
+ root._loading = true;
+
+ url += localeConf.fileExtension;
+
+ $http.get(url)
+ .then(function (data) {
+ var key,
+ path = getPath(token);
+ // Merge the contents of the obtained data into the stored bundle.
+ for (key in data) {
+ if (data.hasOwnProperty(key)) {
+ root[key] = data[key];
+ }
+ }
+
+ // Mark the bundle as having been "loaded".
+ delete root._loading;
+
+ // Notify anyone who cares to know about this event.
+ $rootScope.$broadcast(localeEvents.resourceUpdates);
+
+ // If we issued a Promise for this file, resolve it now.
+ if (deferrences[path]) {
+ deferrences[path].resolve(path);
+ }
+ },
+ function (data) {
+ $log.error("[localizationService] Failed to load: " + url);
+
+ // We can try it again later.
+ delete root._loading;
+ });
+ }
+ }
+ }
+
+ function bundleReady(path) {
+ var bundle,
+ token;
+
+ path = path || localeConf.langFile;
+ token = path + "._LOOKUP_";
+
+ bundle = getBundle(token);
+
+ if (!deferrences[path]) {
+ deferrences[path] = $q.defer();
+ }
+
+ if (bundle && !bundle._loading) {
+ deferrences[path].resolve(path);
+ } else {
+ if (!bundle) {
+ loadBundle(token);
+ }
+ }
+
+ return deferrences[path].promise;
+ }
+
+ function ready(path) {
+ var paths,
+ deferred,
+ outstanding;
+
+ if (angular.isString(path)) {
+ paths = path.split(',');
+ } else if (angular.isArray(path)) {
+ paths = path;
+ } else {
+ throw new Error("locale.ready requires either an Array or comma-separated list.");
+ }
+
+ if (paths.length > 1) {
+ outstanding = [];
+ paths.forEach(function (path) {
+ outstanding.push(bundleReady(path));
+ });
+ deferred = $q.all(outstanding);
+ } else {
+ deferred = bundleReady(path);
+ }
+
+ return deferred;
+ }
+
+ function applySubstitutions(text, subs) {
+ var res = text,
+ firstOfKind = 0;
+
+ if (subs) {
+ if (angular.isArray(subs)) {
+ angular.forEach(subs, function (sub, i) {
+ res = res.replace('%' + (i + 1), sub);
+ res = res.replace('{' + (i + 1) + '}', sub);
+ });
+ } else {
+ angular.forEach(subs, function (v, k) {
+ ++firstOfKind;
+
+ res = res.replace('{' + k + '}', v);
+ res = res.replace('%' + k, v);
+ res = res.replace('%' + (firstOfKind), v);
+ res = res.replace('{' + (firstOfKind) + '}', v);
+ });
+ }
+ }
+ res = res.replace(/\n/g, '
');
+
+ return res;
+ }
+
+ function getLocalizedString(txt, subs) {
+ var result = '',
+ bundle,
+ key,
+ A,
+ isValidToken = false;
+
+ if (angular.isString(txt) && !subs && txt.indexOf(localeConf.delimiter) != -1) {
+ A = txt.split(localeConf.delimiter);
+ txt = A[0];
+ subs = angular.fromJson(A[1]);
+ }
+
+ isValidToken = isToken(txt);
+ if (isValidToken) {
+ if (!angular.isObject(subs)) {
+ subs = [subs];
+ }
+
+ bundle = getBundle(txt);
+ if (bundle && !bundle._loading) {
+ key = getKey(txt);
+
+ if (bundle.data[key]) {
+ result = applySubstitutions(bundle.data[key], subs);
+ } else {
+ $log.info("[localizationService] Key not found: " + txt);
+ result = "%%KEY_NOT_FOUND%%";
+ }
+ } else {
+ if (!bundle) {
+ loadBundle(txt);
+ }
+ }
+ } else {
+ result = txt;
+ }
+
+ return result;
+ }
+
+ function setLocale(value) {
+ var lang;
+
+ if (angular.isString(value)) {
+ value = value.trim();
+ if (localeSupported.indexOf(value) != -1) {
+ lang = value;
+ } else {
+ lang = localeFallbacks[value.split('-')[0]]
+ if (angular.isUndefined(lang)) {
+ lang = localeConf.defaultLocale;
+ }
+ }
+ } else {
+ lang = localeConf.defaultLocale;
+ }
+
+ if (lang != currentLocale) {
+ bundles = {};
+ deferrences = {};
+ currentLocale = lang;
+
+ $rootScope.$broadcast(localeEvents.localeChanges, currentLocale);
+ $rootScope.$broadcast(localeEvents.resourceUpdates);
+
+ if (cookieStore) {
+ cookieStore.put(localeConf.cookieName, lang);
+ }
+ }
+ }
+
+ function getLocale() {
+ return currentLocale;
+ }
+
+ setLocale(cookieStore ? cookieStore.get(localeConf.cookieName) : $window.navigator.userLanguage || $window.navigator.language);
+
+ return {
+ ready: ready,
+ isToken: isToken,
+ getPath: getPath,
+ getKey: getKey,
+ setLocale: setLocale,
+ getLocale: getLocale,
+ getString: getLocalizedString
+ };
+ }
+ ])
+ .filter('i18n', ['locale',
+ function (locale) {
+ var i18nFilter = function (input, args) {
+ return locale.getString(input, args);
+ };
+
+ i18nFilter.$stateful = true;
+
+ return i18nFilter;
+ }
+ ])
+ .directive('i18n', ['$sce', 'locale', 'localeEvents', 'localeConf',
+ function ($sce, locale, localeEvents, localeConf) {
+ function setText(elm, tag) {
+ if (tag !== elm.html()) {
+ elm.html($sce.getTrustedHtml(tag));
+ }
+ }
+
+ function update(elm, string, optArgs) {
+ if (locale.isToken(string)) {
+ locale.ready(locale.getPath(string)).then(function () {
+ setText(elm, locale.getString(string, optArgs));
+ });
+ } else {
+ setText(elm, string);
+ }
+ }
+
+ return function (scope, elm, attrs) {
+ var hasObservers;
+
+ attrs.$observe('i18n', function (newVal, oldVal) {
+ if (newVal && newVal != oldVal) {
+ update(elm, newVal, hasObservers);
+ }
+ });
+
+ angular.forEach(attrs.$attr, function (attr, normAttr) {
+ if (localeConf.observableAttrs.test(attr)) {
+ attrs.$observe(normAttr, function (newVal, oldVal) {
+ if ((newVal && newVal != oldVal) || !hasObservers || !hasObservers[normAttr]) {
+ hasObservers = hasObservers || {};
+ hasObservers[normAttr] = attrs[normAttr];
+ update(elm, attrs.i18n, hasObservers);
+ }
+ });
+ }
+ });
+
+ scope.$on(localeEvents.resourceUpdates, function () {
+ update(elm, attrs.i18n, hasObservers);
+ });
+ scope.$on(localeEvents.localeChanges, function () {
+ update(elm, attrs.i18n, hasObservers);
+ });
+ };
+ }
+ ])
+ .directive('i18nAttr', ['locale', 'localeEvents',
+ function (locale, localeEvents) {
+ return function (scope, elem, attrs) {
+ var lastValues = {};
+
+ function updateText(target, attributes) {
+ var values = scope.$eval(attributes),
+ langFiles = [],
+ exp;
+
+ for(var key in values) {
+ exp = values[key];
+ if (locale.isToken(exp) && langFiles.indexOf(locale.getPath(exp)) == -1) {
+ langFiles.push(locale.getPath(exp));
+ }
+ }
+
+ locale.ready(langFiles).then(function () {
+ var value = '';
+
+ for(var key in values) {
+ exp = values[key];
+ value = locale.getString(exp);
+ if (lastValues[key] !== value) {
+ attrs.$set(key, lastValues[key] = value);
+ }
+ }
+ });
+ }
+
+ attrs.$observe('i18nAttr', function (newVal, oldVal) {
+ if (newVal && newVal != oldVal) {
+ updateText(elem, newVal);
+ }
+ });
+
+ scope.$on(localeEvents.resourceUpdates, function () {
+ updateText(elem, attrs.i18nAttr);
+ });
+ scope.$on(localeEvents.localeChanges, function () {
+ updateText(elem, attrs.i18nAttr);
+ });
+ };
+ }
+ ]);
+angular.module('ngLocalize.InstalledLanguages', [])
+ .value('localeSupported', [
+ 'en-US'
+ ])
+ .value('localeFallbacks', {
+ 'en': 'en-US'
+ });
+angular.module('ngLocalize.Version', [])
+ .constant('localeVer', '1.0.0');
+})(window.angular, window, document);
\ No newline at end of file
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..4f68d71
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,32 @@
+{
+ "name": "angularjs-localization",
+ "version": "1.0.0",
+ "homepage": "https://github.com/angel1st/angularjs-localization",
+ "description": "angularjs localization for AngularJS 1.6+",
+ "main": "angularjs-localization.js",
+ "keywords": [
+ "angularjs",
+ "localization",
+ "i18n",
+ "l10n",
+ "internationalization",
+ "angular",
+ "ng"
+ ],
+ "authors": [
+ "Angel Todorov"
+ ],
+ "license": "MIT",
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "bower_components",
+ "test",
+ "tests"
+ ],
+ "dependencies": {
+ "angular": ">=1.6 < 2",
+ "angular-cookies": ">=1.6 < 2",
+ "angular-sanitize": ">=1.6 < 2"
+ }
+}