diff --git a/packages/tap-i18n/.eslintrc b/packages/tap-i18n/.eslintrc deleted file mode 100644 index 70ccb2981649..000000000000 --- a/packages/tap-i18n/.eslintrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "globals": { - "globals" : true, - "language_names": true, - "TAPi18next" : false - } -} diff --git a/packages/tap-i18n/.gitignore b/packages/tap-i18n/.gitignore deleted file mode 100755 index cff4da41fc45..000000000000 --- a/packages/tap-i18n/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.build* -.npm -.DS_Store -smart.lock -packages/test-pack-* -public -.test-run-log diff --git a/packages/tap-i18n/LICENSE b/packages/tap-i18n/LICENSE deleted file mode 100755 index 8d0265994c9d..000000000000 --- a/packages/tap-i18n/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 TAPevents Asia Limited - -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/packages/tap-i18n/README.md b/packages/tap-i18n/README.md deleted file mode 100755 index 8219a6c58895..000000000000 --- a/packages/tap-i18n/README.md +++ /dev/null @@ -1,808 +0,0 @@ -# tap-i18n - -A comprehensive internationalization solution for Meteor - -### Internationalization for Meteor - -**tap-i18n** is a [Meteor](http://www.meteor.com) package that provides a comprehensive [i18n](http://www.i18nguy.com/origini18n.html) solution for Meteor apps and packages, -with the goal of standardizing the way package developers internationalize their -packages. - -[Watch a talk about tap:i18n & tap:i18n-db](https://www.youtube.com/watch?v=cu_dsoIc_0E) - -**Get involved in tap:i18n:** - -* [Mailing list](http://groups.google.com/d/forum/tap-i18n) -* [tap:i18n chat on Gitter](https://gitter.im/TAPevents/tap-i18n) -* [Roadmap](https://trello.com/b/w80JNkwf/tap-i18n-roadmap) -* [New features planning on Hackpad](https://hackpad.com/collection/DRzcZ7sBdZV) - -Developed by MeteorSpark [Professional Meteor Services](http://www.meteorspark.com)
for TAPevents  Leading Conference Technology. - -**Related Packages:** - -* Check [tap:i18n-db](https://github.com/TAPevents/tap-i18n-db) for Meteor collections internationalization. -* Check [tap:i18n-ui](https://github.com/TAPevents/tap-i18n-ui) for bootstrap based UI components for tap:i18n. -* Check [tap:i18n-bundler](https://github.com/TAPevents/i18n-bundler) for Cordova & static file deployments. - -**Users of tap-i18n v0.9** and below, read [tap:i18n v1.0 New Features & Backward Compatibility](https://github.com/TAPevents/tap-i18n/wiki/tap:i18n-v1.0-New-Feautres-&-Backward-Compatibility) and update your app to v1.0 . - -## Contents - -- [Key Features](#key-features) -- [Quickstart](#quickstart) -- [Documentation & Examples](#documentation--examples) - - [TAPi18n API](#tapi18n-api) - - [The tap-i18n Helpers](#the-tap-i18n-helpers) - - [Languages Tags and Translations Prioritization](#languages-tags-and-translations-prioritization) - - [Structure of Languages Files](#structure-of-languages-files) - - [Configuring tap-i18n](#configuring-tap-i18n) - - [Disabling tap-i18n](#disabling-tap-i18n) - - [Using tap-i18n in Cordova apps](#using-tap-i18n-in-cordova-apps) -- [Developing Packages](#developing-packages) - - [tap-i18n Two Work Modes](#tap-i18n-two-work-modes) - - [Setup tap-i18n](#setup-tap-i18n) - - [Package Level tap-i18n Functions](#package-level-tap-i18n-functions) - - [Using tap-i18n in Your Package Templates](#using-tap-i18n-in-your-package-templates) -- [Unit Testing](#unit-testing) -- [License](#license) -- [Credits](#credits) - -## Key Features - -### All Encompassing - -tap-i18n is designed in a way that distinguishes the role of the package developer, that is, making the package available in multiple languages, from the role of the app developer which is to translate the app, but more importantly, to manage the app's internationalization aspects, such as: setting the supported languages for the project, setting the client language, configuring CDNs for language files, and so on. - -### Readable Syntax - -```handlebars -
{{_ "sign_up"}}
-``` - -### Advanced i18n - -tap-i18n uses [i18next v1.11](http://i18next.github.io/i18next/) as its internationalization engine and exposes all its capabilities to the Meteor's templates - variables, dialects, count/context aware keys, and more. - -**client/messages.html** - -```handlebars - -``` - -**i18n/en.i18n.json** - -```json -{ - "inbox_status": "Hey, %s! You have received one new message today.", - "inbox_status_plural": "Hey, %s! You have received %s new messages today." -} -``` -See more examples below. - -### Transparent Namespacing - -You don't need to worry about domain prefixing or package conflicts when you translate your project or package. Behind the scenes we automatically generate scoped namespaces for you. - -### Ready to Scale - -* Translations are unified into a single JSON file per language that includes both package and project-level translations -* On-demand: translations are loaded only when they are needed -* 3rd Party CDN Support - - -## Quickstart - -**Step 1:** Install tap-i18n using meteor: - -```bash -$ meteor add tap:i18n -``` - -**Step 2:** Add translation helpers to your markup: - -**\*.html** - -```handlebars -
{{_ "hello"}}
-``` - -**Step 3:** Define translations in JSON or YAML format: - -**i18n/en.i18n.json** - -```json -{ "hello": "Hey there" } -``` - -**i18n/fr.i18n.json** - -```json -{ "hello": "Bonjour" } -``` - -**i18n/es.i18n.yml** - -```yaml -hello: Hola -``` - -Translations files should end with lang_tag.i18n.json/yml. - -You can split translations of a certain language to multiple files, we ignore -the prefixed text, e.g., we add the translations of menu.en.i18n.json in the -same way we add those of en.i18n.json . - -You can put languages files anywhere in your project tree, as long as they are -common to both your server and client - **do not put languages files under -/client, /server or /public**. - -Note: Languages files have to be saved in utf-8 encoding. - -**Step 4:** Initiate the client language on startup (optional) - -If you want the client to be served by a specific language on startup - -Assuming that you have a function getUserLanguage() that returns the language -for tag for the current user. - -```javascript -getUserLanguage = function () { - // Put here the logic for determining the user language - - return "fr"; -}; - -if (Meteor.isClient) { - Meteor.startup(function () { - Session.set("showLoadingIndicator", true); - - TAPi18n.setLanguage(getUserLanguage()) - .done(function () { - Session.set("showLoadingIndicator", false); - }) - .fail(function (error_message) { - // Handle the situation - console.log(error_message); - }); - }); -} -``` - -* If you won't set a language on startup your project will be served in the - fallback language: English -* You probably want to show a loading indicator until the language is ready (as - shown in the example), otherwise the templates in your projects will be in - English until the language will be ready - -## Documentation & Examples - -### TAPi18n API - -**TAPi18n.setLanguage(language\_tag) (Client)** - -Sets the client's translation language. - -Returns a jQuery deferred object that resolves if the language load -succeed and fails otherwise. - -**Notes:** - - * language\_tag has to be a supported Language. - * jQuery deferred docs: [jQuery Deferred](http://api.jquery.com/jQuery.Deferred/) - -**TAPi18n.getLanguage() (Client)** - -Returns the tag of the client's current language or null if -tap-i18n is not installed. - -If inside a reactive computation, invalidate the computation the next time the -client language get changed (by TAPi18n.setLanguage) - -**TAPi18n.getLanguages() (Anywhere)** - -Returns an object with all the supported languages and their names. - -A language is considred supported if it is in the supported_languages array of -the project-tap.i18n json. If supported_languages is null or not defined in -project-tap.i18n we consider all the languages we find *.i18n.json/yml files to as -supported. - -The returned object is in the following format: - -```javascript -{ - 'en': { - 'name':'English', // Local name - 'en':'English' // English name - }, - 'zh': { - 'name':'中文' // Local name - 'en':'Chinese' // English name - } - . - . - . -} -``` - -**TAPi18n.__(key, options, lang_tag=null) (Anywhere)** - -*If `lang_tag` is null:* - -Translates key to the current client's language. If inside a reactive -computation, invalidate the computation the next time the client language get -changed (by TAPi18n.setLanguage). - -*Otherwise:* - -Translates key to lang_tag. if you use `lang_tag` you should use `__` in a -reactive computation since the string will be translated to the current client -language if a translator to lang_tag is not ready in the client (if called for -the first time with that lang_tag, or until language data load from the server -finishes) and will get invalidated (trigger reactivity) when the translator to -that lang_tag is ready to be used to translate the key. - -Using `i18next.t` `lng` option or `lang`, which we made as alias to `lang` in -tap:i18n, is equivalent to setting the `lang_tag` attribute. - -The function is a proxy to the i18next.t() method. -Refer to the [documentation of i18next.t()](http://i18next.github.io/i18next/pages/doc_features.html) -to learn about its possible options. (Make sure you refer to i18next v1.11 documentation and not v2) - -**On the server**, TAPi18n.__ is not a reactive resource. You have to specify -the language tag you want to translate the key to. - -**TAPi18n.loadTranslations(translations, namespace="project") (Anywhere)** - -Use *translations* in addition or instead of the translations defined in the -i18n.json files. Translations defined by loadTranslations will have priority -over those defined in language files (i18n.json) of *namespace* (the project, -or package name). - -To enjoy [the benefits of tap:i18n](#key-features), you should use language -files to internationalize your project whenever you can. - -Legitimate cases for *loadTranslations* are: - -* Allowing users to change the project translations -* Changing translations of 3rd party packages that you don't want to fork (see - the Note below). - -Example: - -```javascript -TAPi18n.loadTranslations( - { - es: { - meteor_status_waiting: "Desconectado" - }, - fr: { - meteor_status_failed: "La connexion au serveur a échoué" - } - }, - "francocatena:status" -); -``` - -**Arguments:** - -* `translations`: An object of the following format: - -```javascript -{ - 'lang-tag': { - 'translation-key1': 'translation', - 'translation-key2': 'translation', - ... - }, - ... -} -``` - -* `namespace="project"`: The namespace you want to add the translations to. by - default translations are added to the project namespace, if you want to - change a package translation use the package name as the namespace like the - above example. - -**Notes:** - -* **Adding support to a new language in your app:** You can't use - *addTranslations* in order to add support to a new language, that is, to allow - users to change the interface language of the app to that language. In order - to start support a new language in your app, you'll have to either add a - language file to that language (*.i18n.json file) or add that languages to your - project-tap.i18n file. - -* **Translating a package that uses tap:i18n to another language**: If you want - to add a new language to a 3rd party package (and you can't get it's owner to - merge your pull request) consider introducing a "translation" package in which - package-tap.i18n has the "namespace" options set to the package you are - translating. That way you can translate with languages files instead of - *addTranslations* and share your translation package with others. - -### The tap-i18n Helpers - -### The \_ Helper - -To use tap-i18n to internationalize your templates you can use the \_ helper -that we set on the project's templates and on packages' templates for packages -that uses tap-i18n: - - {{_ "key" "sprintf_arg1" "sprintf_arg2" ... op1="option-value" op2="option-value" ... }} - -**You can customize the helper name, see "Configuring tap-i18n" section.** - -The translation files that will be used to translate key depends on the -template from which it is being used: -* If the helper is being used in a template that belongs to a package that uses - tap-i18n we'll always look for the translation in that package's translation - files. -* If the helper is being used in one of the project's templates we'll look for - the translation in the project's translation files (tap-i18n has to be - installed of course). - -**Usage Examples:** - -Assuming the client language is en. - -**Example 1:** Simple key: - - en.i18n.json: - ------------- - { - "click": "Click Here", - "html_key": "BOLD" - } - - page.html: - ---------- - - - output: - ------- - Click Here - BOLD - -**Example 2:** Simple key specific language: - - en.i18n.json: - ------------- - { - "click": "Click Here" - } - - fr.i18n.json: - ------------- - { - "click": "Cliquez Ici" - } - - page.html (lng and lang options are the same in tap:i18n you can use both): - ---------- - - - - - output: - ------- - Cliquez Ici - -**Example 3:** Sprintf: - - en.i18n.json: - ------------- - { - "hello": "Hello %s, your last visit was on: %s" - } - - page.html: - ---------- - - - output: - ------- - Hello Daniel, your last visit was on: 2014-05-22 - -**Example 4:** Named variables and sprintf: - - en.i18n.json: - ------------- - { - "hello": "Hello __user_name__, your last visit was on: %s" - } - - page.html: - ---------- - - - output: - ------- - Hello Daniel, your last visit was on: 2014-05-22 - -**Note:** Named variables have to be after all the sprintf parameters. - -**Example 5:** Named variables, sprintf, singular/plural: - - en.i18n.json: - ------------- - { - "inbox_status": "__username__, You have a new message (inbox last checked %s)", - "inbox_status_plural": "__username__, You have __count__ new messages (last checked %s)" - } - - page.html: - ---------- - - - output: - ------- - Daniel, You have a new message (inbox last checked 2014-05-22) - Chris, You have 4 new messages (last checked 2014-05-22) - -**Example 6:** Singular/plural, context: - - en.i18n.json: - ------------- - { - "actors_count": "There is one actor in the movie", - "actors_count_male": "There is one actor in the movie", - "actors_count_female": "There is one actress in the movie", - "actors_count_plural": "There are __count__ actors in the movie", - "actors_count_male_plural": "There are __count__ actors in the movie", - "actors_count_female_plural": "There are __count__ actresses in the movie", - } - - page.html: - ---------- - - - output: - ------- - There is one actor in the movie - There is one actor in the movie - There is one actress in the movie - There are 2 actors in the movie - There are 2 actors in the movie - There are 2 actresses in the movie - -* Refer to the [documentation of i18next.t() v1.11](http://i18next.github.io/i18next/pages/doc_features.html) - to learn more about its possible options. (Make sure you refer to i18next v1.11 documentation and not v2) -* The translation will get updated automatically after calls to - TAPi18n.setLanguage(). - -### More helpers - -**{{languageTag}}:** - -The {{languageTag}} helper calls TAPi18n.getLanguage(). - -It's useful when you need to load assets depending on the current language, for -example: - -```handlebars - -``` - -### Languages Tags and Translations Prioritization - -We use the [IETF language tag system](http://en.wikipedia.org/wiki/IETF_language_tag) -for languages tagging. With it developers can refer to a certain language or -pick one of its dialects. - -Example: A developer can either refer to English in general using: "en" or to -use the Great Britain dialect with "en-GB". - -**If tap-i18n is install** we'll attempt to look for a translation of a certain -string in the following order: -* Language dialect, if specified ("pt-BR") -* Base language ("pt") -* Base English ("en") - -**Notes:** - -* We currently support only one dialect level. e.g. nan-Hant-TW is not - supported. -* "en-US" is the dialect we use for the base English translations "en". -* If tap-i18n is not installed, packages will be served in English, the fallback language. - -### Structure of Languages Files - -Languages files should be named: arbitrary.text.lang_tag.i18n.json . e.g., en.i18n.json, menu.pt-BR.i18n.json. - -You can have more than one file for the same language. - -You can put languages files anywhere in your project tree, as long as they are -common to both your server and client - **do not put languages files under -/client, /server or /public**. - -Example for languages files: - - en.i18n.json - { - "sky": "Sky", - "color": "Color" - } - - pt.i18n.json - { - "sky": "Céu", - "color": "Cor" - } - - fr.i18n.json - { - "sky": "Ciel" - } - - en-GB.i18n.json - { - "color": "Colour" - } - -* Do not use colons and periods (see note below) in translation keys. -* To avoid translation bugs all the keys in your package must be translated to - English ("en") which is the fallback language we use if tap-i18n is not installed, - or when we can't find a translation for a certain key. -* In the above example there is no need to translate "sky" in en-GB which is the - same in en. Remember that thanks to the Languages Tags and Translations - Prioritization (see above) if a translation for a certain key is the same for a - language and one of its dialects you don't need to translate it again in the - dialect file. -* The French file above have no translation for the color key above, it will - fallback to English. -* Check [i18next features documentation](http://i18next.github.io/i18next/pages/doc_features.html) for - more advanced translations structures you can use in your JSONs files (Such as - variables, plural form, etc.). (Make sure you refer to i18next v1.11 documentation and not v2) - -#### A note about dot notation - -Note that `{_ "foo.bar"}` will be looked under `{foo: {bar: "Hello World"}}`, and not under `"foo.bar"`. - -### Configuring tap-i18n - -To configure tap-i18n add to it a file named **project-tap.i18n**. - -This JSON can have the following properties. All of them are optional. The values bellow -are the defaults. - - project-root/project-tap.i18n - ----------------------------- - { - "helper_name": "_", - "supported_languages": null, - "i18n_files_route": "/tap-i18n", - "cdn_path": null, - "preloaded_langs": [] - } - -Options: - -**helper\_name:** the name for the templates' translation helper. - -**supported\_languages:** A list of languages tags you want to make available on -your project. If null, all the languages we'll find translation files for, in the -project, will be available. - -**build\_files\_path:** Can be an absolute path or relative to the project's root. If you change this value we assume you want to serve the files yourself (via cdn, or by other means) so we won't initiate the tap-i18n's built-in files server. Therefore if you set build\_files\_path you **must** set the browser\_path. - -**i18n\_files\_route:** The route in which the tap-i18n resources will be available in the project. - -**cdn\_path:** An alternative path from which you want tap-i18n resources to be loaded. Example: "http://cdn.example.com/tap-i18n". - -**preloaded_langs:** An array of languages tags. If isn't empty, a single synchronous ajax requrest will load the translation strings for all the languages tags listed. If you want to load all the supported languages set preloaded_langs to `["*"]` (`"*"` must be the first item of the array, the rest of the array will be ignored. `["zh-*"]` won't work). - -**Notes:** - -* We use AJAX to load the languages files so you'll have to set CORS on your CDN. - -### Disabling tap-i18n - -**Step 1:** Remove tap-i18n method calls from your project. - -**Step 2:** Remove tap-i18n package - -```bash -$ meteor remove tap:i18n -``` - -### Using tap-i18n in Cordova apps - -In order to use tap-i18n in a Cordova app you must set the `--server` flag -to your server's root url when building your project. - -```bash -$ meteor build --server="http://www.your-site-domain.com" -``` - -If your app should work when the user is offline, install the [tap:i18n-bundler](https://atmospherejs.com/tap/i18n-bundler) package and follow [its instructions](https://github.com/TAPevents/i18n-bundler#usage). - -## Developing Packages - -Though the decision to translate a package and to internationalize it is a -decision made by the **package** developer, the control over the -internationalization configurations are done by the **project** developer and -are global to all the packages within the project. - -Therefore if you wish to use tap-i18n to internationalize your Meteor -package your docs will have to refer projects developers that will use it to -the "Usage - Project Developers" section above to enable internationalization. -If the project developer won't enable tap-i18n your package will be served in -the fallback language English. - -### tap-i18n Two Work Modes - -tap-i18n can be used to internationalize projects and packages, but its -behavior is determined by whether or not it's installed on the project level. -We call these two work modes: *enabled* and *disabled*. - -When tap-i18n is disabled we don't unify the languages files that the packages -being used by the project uses, and serve all the packages in the fallback -language (English) - -### Setup tap-i18n - -In order to use tap-i18n to internationalize your package: - -**Step 1:** Add the package-tap.i18n configuration file: - -You can use empty file or an empty JSON object if you don't need to change them. - -The values below are the defaults. - - package_dir/package-tap.i18n - ---------------------------- - { - // The name for the translation function that - // will be available in package's namespace. - "translation_function_name": "__", - - // the name for the package templates' translation helper - "helper_name": "_", - - // directory for the translation files (without leading slash) - "languages_files_dir": "i18n", - - // tap:i18n automatically separates the translation strings of each package to a - // namespace dedicated to that package, which is used by the package's translation - // function and helper. Use the namespace option to set a custom namespace for - // the package. By using the name of another package you can use your package to - // add to that package or modify its translations. You can also set the namespace to - // "project" to add translations that will be available in the project level. - "namespace": null - } - -**Step 2:** Create your languages\_files\_dir: - -Example for the default languages\_files\_dir path and its structure: - - . - |--package_name - |----package.js - |----package-tap.i18n - |----i18n # Should be the same path as languages_files_dir option above - |------en.i18n.json - |------fr.i18n.json - |------pt.i18n.json - |------pt-BR.i18n.json - . - . - . - -NOTE: the file for the fallback language (`en.i18n.json`) **must** exist (it may be empty though). - -The leanest set up (for instance in a private package, where you keep the translations at the project level) is two empty files: `package-tap.i18n` and `i18n/en.i18n.json`. - -**Step 3:** Setup your package.js: - -Your package's package.js should be structured as follow: - - Package.on_use(function (api) { - api.use(["tap:i18n@1.0.7"], ["client", "server"]); - - . - . - . - - // You must load your package's package-tap.i18n before you load any - // template - api.add_files("package-tap.i18n", ["client", "server"]); - - // Templates loads (if any) - - // List your languages files so Meteor will watch them and rebuild your - // package as they change. - // You must load the languages files after you load your templates - - // otherwise the templates won't have the i18n capabilities (unless - // you'll register them with tap-i18n yourself, see below). - api.add_files([ - "i18n/en.i18n.json", - "i18n/fr.i18n.json", - "i18n/pt.i18n.json", - "i18n/pt-br.i18n.json" - ], ["client", "server"]); - }); - -Note: en, which is the fallback language, is the only language we integrate -into the clients bundle. All the other languages files will be loaded only -to the server bundle and will be served as part of the unified languages files, -that contain all the project's translations. - -### Package Level tap-i18n Functions - -The following functions are added to your package namespace by tap-i18n: - -**\_\_("key", options, lang_tag) (Anywhere)** - -Read documenation for `TAPi18n.__` above. - -**On the server**, TAPi18n.__ is not a reactive resource. You have to specify -the language tag you want to translate the key to. - -You can use package-tap.i18n to change the name of this function. - -**registerI18nHelper(template\_name) (Client)** - -**registerTemplate(template\_name) (Client) [obsolete alias, will be removed in future versions]** - -Register the \_ helper that maps to the \_\_ function for the -template with the given name. - -**Important:** As long as you load the package templates after you add package-tap.i18n -and before you start adding the languages files you won't need to register templates yourself. - -### Using tap-i18n in Your Package Templates - -See "The tap-i18n helper" section above. - -## Unit Testing - -See /unittest/test-packages/README.md . - -## License - -MIT - -## Author - -[Daniel Chcouri](http://theosp.github.io/) - -## Contributors - -* [Chris Hitchcott](https://github.com/hitchcott/) -* [Kevin Iamburg](http://www.slickdevelopment.com) -* [Abe Pazos](https://github.com/hamoid/) -* [@karfield](https://github.com/karfield/) -* [@nscarcella](https://github.com/nscarcella/) -* [@mpowaga](https://github.com/mpowaga/) - -## Credits - -* [i18next v1.11](http://i18next.github.io/i18next/) -* [simple-schema](https://github.com/aldeed/meteor-simple-schema) -* [http-methods](https://github.com/CollectionFS/Meteor-http-methods) diff --git a/packages/tap-i18n/TODO b/packages/tap-i18n/TODO deleted file mode 100755 index edc654412135..000000000000 --- a/packages/tap-i18n/TODO +++ /dev/null @@ -1,3 +0,0 @@ -TODO: - -* Add memcache layer to the integral file server diff --git a/packages/tap-i18n/lib/globals.js b/packages/tap-i18n/lib/globals.js deleted file mode 100755 index 637d36c8c3f6..000000000000 --- a/packages/tap-i18n/lib/globals.js +++ /dev/null @@ -1,12 +0,0 @@ -// The globals object will be accessible to the build plugin, the server and -// the client - -/* eslint no-unused-vars: 0 */ - -globals = { - fallback_language: 'en', - langauges_tags_regex: '([a-z]{2})(-[A-Z]{2})?', - project_translations_domain: 'project', - browser_path: '/tap-i18n', - debug: false, -}; diff --git a/packages/tap-i18n/lib/plugin/compiler_configuration.coffee b/packages/tap-i18n/lib/plugin/compiler_configuration.coffee deleted file mode 100755 index e3677703f876..000000000000 --- a/packages/tap-i18n/lib/plugin/compiler_configuration.coffee +++ /dev/null @@ -1,23 +0,0 @@ -# Note: same compiler can be used to compile more then one package (at least in v0.9.x) - -share.compiler_configuration = - fallback_language: globals.fallback_language - packages: [] # Each time we compile package-tap.i18n we push "package_name:arch" to this array - templates_registered_for: [] # Each time we register a template we push "package_name:arch" to this array - default_project_conf_inserted_for: [] # Keeps track of the archs we've inserted the default project conf for. - # Default project conf is inserted by the *.i18.json compiler to be used - # in case the project has no project-tap.i18n - project_tap_i18n_loaded_for: [] # Keeps track of the archs we've loaded project_tap_i18n for - - tap_i18n_input_files: [] - registerInputFile: (compileStep) -> - input_file = "#{compileStep.arch}:#{compileStep._fullInputPath}" - if input_file in @tap_i18n_input_files - # A new build cycle - @packages = [] - @templates_registered_for = [] - @default_project_conf_inserted_for = [] - @project_tap_i18n_loaded_for = [] - @tap_i18n_input_files = [] - - @tap_i18n_input_files.push(input_file) diff --git a/packages/tap-i18n/lib/plugin/compilers/i18n.coffee b/packages/tap-i18n/lib/plugin/compilers/i18n.coffee deleted file mode 100755 index 37d6f3027835..000000000000 --- a/packages/tap-i18n/lib/plugin/compilers/i18n.coffee +++ /dev/null @@ -1,18 +0,0 @@ -path = Npm.require "path" - -compilers = share.compilers - -Plugin.registerSourceHandler "i18n", (compileStep) -> - # Starting from Meteor v1.2 registerSourceHandler doesn't - # accept filenames as handlers. - # See: https://github.com/meteor/meteor/issues/3985 - # and: https://github.com/TAPevents/tap-i18n/issues/113 - # Below is a workaround until we refactor for v1.2 new - # build plugin API. - file_name = _.last compileStep.inputPath.split(path.sep) - - if file_name == "package-tap.i18n" - compilers.package_tap_i18n(compileStep) - - if file_name == "project-tap.i18n" - compilers.project_tap_i18n(compileStep) diff --git a/packages/tap-i18n/lib/plugin/compilers/i18n.generic_compiler.coffee b/packages/tap-i18n/lib/plugin/compilers/i18n.generic_compiler.coffee deleted file mode 100755 index 86199b861f62..000000000000 --- a/packages/tap-i18n/lib/plugin/compilers/i18n.generic_compiler.coffee +++ /dev/null @@ -1,124 +0,0 @@ -path = Npm.require "path" - -helpers = share.helpers -compilers = share.compilers -compiler_configuration = share.compiler_configuration - -compilers.generic_compiler = (extension, helper) -> (compileStep) -> - compiler_configuration.registerInputFile(compileStep) - input_path = compileStep._fullInputPath - - language = path.basename(input_path).split(".").slice(0, -2).pop() - if _.isUndefined(language) or _.isEmpty(language) - compileStep.error - message: "Language-tag is not specified for *.i18n.`#{extension}' file: `#{input_path}'", - sourcePath: input_path - return - - if not RegExp("^#{globals.langauges_tags_regex}$").test(language) - compileStep.error - message: "Can't recognise '#{language}' as a language-tag: `#{input_path}'", - sourcePath: input_path - return - - translations = helper input_path, compileStep - - package_name = if helpers.isPackage(compileStep) then compileStep.packageName else globals.project_translations_domain - output = - """ - var _ = Package.underscore._, - package_name = "#{package_name}", - namespace = "#{package_name}"; - - if (package_name != "#{globals.project_translations_domain}") { - namespace = TAPi18n.packages[package_name].namespace; - } - - """ - - # only for project - if not helpers.isPackage(compileStep) - if /^(client|server)/.test(compileStep.inputPath) - compileStep.error - message: "Languages files should be common to the server and the client. Do not put them under /client or /server .", - sourcePath: input_path - return - - # add the language names to TAPi18n.languages_names - language_name = [language, language] - if language_names[language]? - language_name = language_names[language] - - if language != globals.fallback_language - # the name for the fallback_language is part of the getProjectConfJs()'s output - output += - """ - TAPi18n.languages_names["#{language}"] = #{JSON.stringify language_name}; - - """ - - # If this is a project but project-tap.i18n haven't compiled yet add default project conf - # for case there is no project-tap.i18n defined in this project. - # Reminder: we don't require projects to have project-tap.i18n - if not(helpers.isDefaultProjectConfInserted(compileStep)) and \ - not(helpers.isProjectI18nLoaded(compileStep)) - output += share.getProjectConfJs(share.project_i18n_schema.clean {}) # defined in project-tap.i18n.coffee - - helpers.markDefaultProjectConfInserted(compileStep) - - - # if fallback_language -> integrate, otherwise add to TAPi18n.translations if server arch. - if language == compiler_configuration.fallback_language - output += - """ - // integrate the fallback language translations - translations = {}; - translations[namespace] = #{JSON.stringify translations}; - TAPi18n._loadLangFileObject("#{compiler_configuration.fallback_language}", translations); - - """ - - if compileStep.archMatches "os" - if language != compiler_configuration.fallback_language - output += - """ - if(_.isUndefined(TAPi18n.translations["#{language}"])) { - TAPi18n.translations["#{language}"] = {}; - } - - if(_.isUndefined(TAPi18n.translations["#{language}"][namespace])) { - TAPi18n.translations["#{language}"][namespace] = {}; - } - - _.extend(TAPi18n.translations["#{language}"][namespace], #{JSON.stringify translations}); - - """ - - output += - """ - TAPi18n._registerServerTranslator("#{language}", namespace); - - """ - - # register i18n helper for templates, only once per web arch, only for packages - if helpers.isPackage(compileStep) - if compileStep.archMatches("web") and helpers.getCompileStepArchAndPackage(compileStep) not in compiler_configuration.templates_registered_for - output += - """ - var package_templates = _.difference(_.keys(Template), non_package_templates); - - for (var i = 0; i < package_templates.length; i++) { - var package_template = package_templates[i]; - - registerI18nTemplate(package_template); - } - - """ - compiler_configuration.templates_registered_for.push helpers.getCompileStepArchAndPackage(compileStep) - - output_path = compileStep.rootOutputPath + compileStep.inputPath.replace new RegExp("`#{extension}'$"), "js" - compileStep.addJavaScript - path: output_path, - sourcePath: input_path, - data: output, - bare: false \ No newline at end of file diff --git a/packages/tap-i18n/lib/plugin/compilers/i18n.json.coffee b/packages/tap-i18n/lib/plugin/compilers/i18n.json.coffee deleted file mode 100755 index fe65e24a02ab..000000000000 --- a/packages/tap-i18n/lib/plugin/compilers/i18n.json.coffee +++ /dev/null @@ -1,4 +0,0 @@ -helpers = share.helpers -compilers = share.compilers -compilers.i18n_json = compilers.generic_compiler('json', helpers.loadJSON) -Plugin.registerSourceHandler "i18n.json", compilers.i18n_json \ No newline at end of file diff --git a/packages/tap-i18n/lib/plugin/compilers/i18n.yml.coffee b/packages/tap-i18n/lib/plugin/compilers/i18n.yml.coffee deleted file mode 100755 index ec7e7f79362f..000000000000 --- a/packages/tap-i18n/lib/plugin/compilers/i18n.yml.coffee +++ /dev/null @@ -1,4 +0,0 @@ -helpers = share.helpers -compilers = share.compilers -compilers.i18n_yml = compilers.generic_compiler('yml', helpers.loadYAML) -Plugin.registerSourceHandler "i18n.yml", compilers.i18n_yml \ No newline at end of file diff --git a/packages/tap-i18n/lib/plugin/compilers/package-tap.i18n.coffee b/packages/tap-i18n/lib/plugin/compilers/package-tap.i18n.coffee deleted file mode 100755 index 45db1a679c60..000000000000 --- a/packages/tap-i18n/lib/plugin/compilers/package-tap.i18n.coffee +++ /dev/null @@ -1,95 +0,0 @@ -helpers = share.helpers -compilers = share.compilers -compiler_configuration = share.compiler_configuration - -schema = new SimpleSchema - translation_function_name: - type: String - defaultValue: "__" - label: "Translation Function Name" - optional: true - helper_name: - type: String - defaultValue: "_" - label: "Helper Name" - optional: true - namespace: - type: String - defaultValue: null - label: "Translations Namespace" - optional: true - -compilers.package_tap_i18n = (compileStep) -> - compiler_configuration.registerInputFile(compileStep) - input_path = compileStep._fullInputPath - - if helpers.isPackage(compileStep) - compileStep.error - message: "More than one package-tap.i18n found for package: #{compileStep.packageName}", - sourcePath: input_path - return - - if helpers.isProjectI18nLoaded(compileStep) - compileStep.error - message: "Can't compile package-tap.i18n if project-tap.i18n is present", - sourcePath: input_path - return - - if helpers.isDefaultProjectConfInserted(compileStep) - compileStep.error - message: "package-tap.i18n should be loaded before languages files (*.i18n.json)", - sourcePath: input_path - return - - helpers.markAsPackage(compileStep) - - package_tap_i18n = helpers.loadJSON input_path, compileStep - - if not package_tap_i18n? - package_tap_i18n = schema.clean {} - schema.clean package_tap_i18n - - try - check package_tap_i18n, schema - catch error - compileStep.error - message: "File `#{file_path}' is an invalid package-tap.i18n file (#{error})", - sourcePath: input_path - return - - package_name = compileStep.packageName - - if not package_tap_i18n.namespace? - package_tap_i18n.namespace = package_name - - namespace = package_tap_i18n.namespace - - package_i18n_js_file = - """ - TAPi18n.packages["#{package_name}"] = #{JSON.stringify(package_tap_i18n)}; - - // define package's translation function (proxy to the i18next) - #{package_tap_i18n.translation_function_name} = TAPi18n._getPackageI18nextProxy("#{namespace}"); - - """ - - if compileStep.archMatches "web" - package_i18n_js_file += - """ - // define the package's templates registrar - registerI18nTemplate = TAPi18n._getRegisterHelpersProxy("#{package_name}"); - registerTemplate = registerI18nTemplate; // XXX OBSOLETE, kept for backward compatibility will be removed in the future - - // Record the list of templates prior to package load - var _ = Package.underscore._; - non_package_templates = _.keys(Template); - - """ - - compileStep.addJavaScript - path: "package-i18n.js", - sourcePath: input_path, - data: package_i18n_js_file, - bare: false - -Plugin.registerSourceHandler "package-tap.i18n", compilers.package_tap_i18n \ No newline at end of file diff --git a/packages/tap-i18n/lib/plugin/compilers/project-tap.i18n.coffee b/packages/tap-i18n/lib/plugin/compilers/project-tap.i18n.coffee deleted file mode 100755 index 0187d7161a5e..000000000000 --- a/packages/tap-i18n/lib/plugin/compilers/project-tap.i18n.coffee +++ /dev/null @@ -1,122 +0,0 @@ -helpers = share.helpers -compilers = share.compilers -compiler_configuration = share.compiler_configuration - -share.project_i18n_schema = schema = new SimpleSchema - helper_name: - type: String - defaultValue: "_" - label: "Helper Name" - optional: true - supported_languages: - type: [String] - label: "Supported Languages" - defaultValue: null - optional: true - i18n_files_route: - type: String - label: "Unified languages files path" - defaultValue: globals.browser_path - optional: true - preloaded_langs: - type: [String] - label: "Preload languages" - defaultValue: [] - optional: true - cdn_path: - type: String - label: "Unified languages files path on CDN" - defaultValue: null - optional: true - -getProjectConfJs = share.getProjectConfJs = (conf) -> - fallback_language_name = language_names[globals.fallback_language] - - project_conf_js = """ - TAPi18n._enable(#{JSON.stringify(conf)}); - TAPi18n.languages_names["#{globals.fallback_language}"] = #{JSON.stringify fallback_language_name}; - - """ - - # If we get a list of supported languages we must make sure that we'll have a - # language name for each one of its languages. - # - # Though languages names are added for every language we find i18n.json file - # for (by the i18n.json compiler). We shouldn't rely on the existence of - # *.i18n.json file for each supported language, because a language might be - # defined as supported even when it has no i18n.json files (it's especially - # true when tap:i18n is used with tap:i18n-db) - if conf.supported_languages? - for lang_tag in conf.supported_languages - if language_names[lang_tag]? - project_conf_js += """ - TAPi18n.languages_names["#{lang_tag}"] = #{JSON.stringify language_names[lang_tag]}; - - """ - - return project_conf_js - -compilers.project_tap_i18n = (compileStep) -> - compiler_configuration.registerInputFile(compileStep) - input_path = compileStep._fullInputPath - - if helpers.isPackage(compileStep) - compileStep.error - message: "Can't load project-tap.i18n in a package: #{compileStep.packageName}", - sourcePath: input_path - return - - if helpers.isProjectI18nLoaded(compileStep) - compileStep.error - message: "Can't have more than one project-tap.i18n", - sourcePath: input_path - return - - project_tap_i18n = helpers.loadJSON input_path, compileStep - - if not project_tap_i18n? - project_tap_i18n = schema.clean {} - schema.clean project_tap_i18n - - try - check project_tap_i18n, schema - catch error - compileStep.error - message: "File `#{file_path}' is an invalid project-tap.i18n file (#{error})", - sourcePath: input_path - return - - project_i18n_js_file = getProjectConfJs project_tap_i18n - - if compileStep.archMatches("web") and not _.isEmpty project_tap_i18n.preloaded_langs - preloaded_langs = "all" - if project_tap_i18n.preloaded_langs[0] != "*" - preloaded_langs = project_tap_i18n.preloaded_langs.join(",") - - project_i18n_js_file += - """ - $.ajax({ - type: 'GET', - url: "#{project_tap_i18n.i18n_files_route}/multi/#{preloaded_langs}.json", - dataType: 'json', - success: function(data) { - for (lang_tag in data) { - TAPi18n._loadLangFileObject(lang_tag, data[lang_tag]); - TAPi18n._loaded_languages.push(lang_tag); - } - }, - data: {}, - async: false - }); - - """ - - helpers.markProjectI18nLoaded(compileStep) - - compileStep.addJavaScript - path: "project-i18n.js", - sourcePath: input_path, - data: project_i18n_js_file, - bare: false - -Plugin.registerSourceHandler "project-tap.i18n", compilers.project_tap_i18n \ No newline at end of file diff --git a/packages/tap-i18n/lib/plugin/compilers/share.coffee b/packages/tap-i18n/lib/plugin/compilers/share.coffee deleted file mode 100755 index 6216e2839501..000000000000 --- a/packages/tap-i18n/lib/plugin/compilers/share.coffee +++ /dev/null @@ -1 +0,0 @@ -share.compilers = {} \ No newline at end of file diff --git a/packages/tap-i18n/lib/plugin/etc/language_names.js b/packages/tap-i18n/lib/plugin/etc/language_names.js deleted file mode 100755 index 8996a1181ee5..000000000000 --- a/packages/tap-i18n/lib/plugin/etc/language_names.js +++ /dev/null @@ -1,139 +0,0 @@ -/* eslint no-unused-vars: 0 */ - -language_names = { - af: ['Afrikaans', 'Afrikaans'], - ak: ['Akan', 'Akan'], - sq: ['Albanian', 'Shqip'], - am: ['Amharic', 'አማርኛ'], - ar: ['Arabic', 'العربية'], - hy: ['Armenian', 'Հայերեն'], - rup: ['Aromanian', 'Armãneashce'], - as: ['Assamese', 'অসমীয়া'], - az: ['Azerbaijani', 'Azərbaycan dili'], - 'az-TR': ['Azerbaijani (Turkey)', 'Azərbaycan Türkcəsi'], - ba: ['Bashkir', 'башҡорт теле'], - eu: ['Basque', 'Euskara'], - 'be-BY': ['Belarusian', 'Беларуская мова'], - bn: ['Bengali', 'বাংলা'], - bs: ['Bosnian', 'Bosanski'], - bg: ['Bulgarian', 'Български'], - mya: ['Burmese', 'ဗမာစာ'], - ca: ['Catalan', 'Català'], - bal: ['Catalan (Balear)', 'Català (Balear)'], - zh: ['Chinese', '中文'], - 'zh-CN': ['Chinese (China)', '简体中文'], - 'zh-HK': ['Chinese (Hong Kong)', '繁體中文(香港)'], - 'zh-TW': ['Chinese (Taiwan)', '繁體中文(台灣)'], - co: ['Corsican', 'corsu'], - hr: ['Croatian', 'Hrvatski'], - cs: ['Czech', 'čeština‎'], - da: ['Danish', 'Dansk'], - nl: ['Dutch', 'Nederlands'], - 'nl-BE': ['Dutch (Belgium)', 'Nederlands (België)'], - en: ['English', 'English'], - 'en-AU': ['English (Australia)', 'English (Australia)'], - 'en-CA': ['English (Canada)', 'English (Canada)'], - 'en-GB': ['English (UK)', 'English (UK)'], - eo: ['Esperanto', 'Esperanto'], - et: ['Estonian', 'Eesti'], - fo: ['Faroese', 'føroyskt'], - fi: ['Finnish', 'Suomi'], - 'fr-BE': ['French (Belgium)', 'Français de Belgique'], - fr: ['French (France)', 'Français'], - fy: ['Frisian', 'Frysk'], - fuc: ['Fulah', 'Pulaar'], - gl: ['Galician', 'Galego'], - ka: ['Georgian', 'ქართული'], - de: ['German', 'Deutsch'], - 'de-AT': ['German (Austria)', 'Östereichisches Deutsch'], - 'de-IN': ['German (informal)', 'Deutsch (informell)'], - el: ['Greek', 'Ελληνικά'], - gn: ['Guaraní', 'Avañe\'ẽ'], - haw: ['Hawaiian', 'Ōlelo Hawaiʻi'], - haz: ['Hazaragi', 'هزاره گی'], - he: ['Hebrew', 'עברית'], - hi: ['Hindi', 'हिन्दी'], - hu: ['Hungarian', 'Magyar'], - is: ['Icelandic', 'Íslenska'], - id: ['Indonesian', 'Bahasa Indonesia'], - ga: ['Irish', 'Gaelige'], - it: ['Italian', 'Italiano'], - ja: ['Japanese', '日本語'], - jv: ['Javanese', 'Basa Jawa'], - kn: ['Kannada', 'ಕನ್ನಡ'], - kk: ['Kazakh', 'Қазақ тілі'], - km: ['Khmer', 'ភាសាខ្មែរ'], - rw: ['Kinyarwanda', 'Kinyarwanda'], - ky: ['Kirghiz', 'кыргыз тили'], - ko: ['Korean', '한국어'], - ku: ['Kurdish (Sorani)', 'كوردی‎'], - lo: ['Lao', 'ພາສາລາວ'], - lv: ['Latvian', 'latviešu valoda'], - li: ['Limburgish', 'Limburgs'], - lt: ['Lithuanian', 'Lietuvių kalba'], - lb: ['Luxembourgish', 'Lëtzebuergesch'], - mk: ['Macedonian', 'македонски јазик'], - mg: ['Malagasy', 'Malagasy'], - 'ms-MY': ['Malay', 'Bahasa Melayu'], - ml: ['Malayalam', 'മലയാളം'], - mr: ['Marathi', 'मराठी'], - xmf: ['Mingrelian', 'მარგალური ნინა'], - mn: ['Mongolian', 'Монгол'], - me: ['Montenegrin', 'Crnogorski jezik'], - ne: ['Nepali', 'नेपाली'], - no: ['Norwegian', 'Norsk'], - os: ['Ossetic', 'Ирон'], - ps: ['Pashto', 'پښتو'], - fa: ['Persian', 'فارسی'], - 'fa-AF': ['Persian (Afghanistan)', 'فارسی (افغانستان'], - pl: ['Polish', 'Polski'], - 'pt-BR': ['Portuguese (Brazil)', 'Português do Brasil'], - pt: ['Portuguese (Portugal)', 'Português'], - pa: ['Punjabi', 'ਪੰਜਾਬੀ'], - rhg: ['Rohingya', 'Rohingya'], - ro: ['Romanian', 'Română'], - ru: ['Russian', 'Русский'], - rue: ['Rusyn', 'Русиньскый'], - sah: ['Sakha', 'Sakha'], - 'sa-IN': ['Sanskrit', 'भारतम्'], - srd: ['Sardinian', 'sardu'], - gd: ['Scottish Gaelic', 'Gàidhlig'], - sr: ['Serbian', 'Српски језик'], - sd: ['Sindhi', 'سندھ'], - si: ['Sinhala', 'සිංහල'], - 'sk-SK': ['Slovak', 'Slovenčina'], - 'sl-SI': ['Slovenian', 'slovenščina'], - so: ['Somali', 'Afsoomaali'], - azb: ['South Azerbaijani', 'گؤنئی آذربایجان'], - 'es-AR': ['Spanish (Argentina)', 'Español de Argentina'], - 'es-CL': ['Spanish (Chile)', 'Español de Chile'], - 'es-CO': ['Spanish (Colombia)', 'Español de Colombia'], - 'es-MX': ['Spanish (Mexico)', 'Español de México'], - 'es-PE': ['Spanish (Peru)', 'Español de Perú'], - 'es-PR': ['Spanish (Puerto Rico)', 'Español de Puerto Rico'], - es: ['Spanish (Spain)', 'Español'], - 'es-VE': ['Spanish (Venezuela)', 'Español de Venezuela'], - su: ['Sundanese', 'Basa Sunda'], - sw: ['Swahili', 'Kiswahili'], - sv: ['Swedish', 'Svenska'], - gsw: ['Swiss German', 'Schwyzerdütsch'], - tl: ['Tagalog', 'Tagalog'], - tg: ['Tajik', 'тоҷикӣ'], - 'ta-IN': ['Tamil', 'தமிழ்'], - 'ta-LK': ['Tamil (Sri Lanka)', 'தமிழ்'], - tt: ['Tatar', 'Татар теле'], - te: ['Telugu', 'తెలుగు'], - 'th-TH': ['Thai', 'ไทย'], - bo: ['Tibetan', 'བོད་སྐད'], - tir: ['Tigrinya', 'ትግርኛ'], - tr: ['Turkish', 'Türkçe'], - tuk: ['Turkmen', 'Türkmençe'], - ua: ['Ukrainian', 'Українська'], - ug: ['Uighur', 'Uyƣurqə'], - uk: ['Ukrainian', 'Українська'], - ur: ['Urdu', 'اردو'], - uz: ['Uzbek', 'O‘zbekcha'], - 'vi-VN': ['Vietnamese', 'Tiếng Việt'], - wa: ['Walloon', 'Walon'], - cy: ['Welsh', 'Cymraeg'], -}; diff --git a/packages/tap-i18n/lib/plugin/helpers/compile_step_helpers.coffee b/packages/tap-i18n/lib/plugin/helpers/compile_step_helpers.coffee deleted file mode 100755 index 0ab5a6f58a10..000000000000 --- a/packages/tap-i18n/lib/plugin/helpers/compile_step_helpers.coffee +++ /dev/null @@ -1,23 +0,0 @@ -compiler_configuration = share.compiler_configuration - -_.extend share.helpers, - getCompileStepArchAndPackage: (compileStep) -> - "#{compileStep.packageName}:#{compileStep.arch}" - - markAsPackage: (compileStep) -> - compiler_configuration.packages.push @.getCompileStepArchAndPackage(compileStep) - - isPackage: (compileStep) -> - @.getCompileStepArchAndPackage(compileStep) in compiler_configuration.packages - - markProjectI18nLoaded: (compileStep) -> - compiler_configuration.project_tap_i18n_loaded_for.push @.getCompileStepArchAndPackage(compileStep) - - isProjectI18nLoaded: (compileStep) -> - @.getCompileStepArchAndPackage(compileStep) in compiler_configuration.project_tap_i18n_loaded_for - - markDefaultProjectConfInserted: (compileStep) -> - compiler_configuration.default_project_conf_inserted_for.push @.getCompileStepArchAndPackage(compileStep) - - isDefaultProjectConfInserted: (compileStep) -> - @.getCompileStepArchAndPackage(compileStep) in compiler_configuration.default_project_conf_inserted_for diff --git a/packages/tap-i18n/lib/plugin/helpers/helpers.coffee b/packages/tap-i18n/lib/plugin/helpers/helpers.coffee deleted file mode 100755 index 74aff3ad7007..000000000000 --- a/packages/tap-i18n/lib/plugin/helpers/helpers.coffee +++ /dev/null @@ -1 +0,0 @@ -share.helpers = {} \ No newline at end of file diff --git a/packages/tap-i18n/lib/plugin/helpers/load_json.coffee b/packages/tap-i18n/lib/plugin/helpers/load_json.coffee deleted file mode 100755 index 6ecc5af655d7..000000000000 --- a/packages/tap-i18n/lib/plugin/helpers/load_json.coffee +++ /dev/null @@ -1,24 +0,0 @@ -fs = Npm.require 'fs' - -# loads a json from file_path -# -# returns undefined if file doesn't exist null if file is empty, parsed content otherwise -_.extend share.helpers, - loadJSON: (file_path, compileStep=null) -> - try # use try/catch to avoid the additional syscall to fs.existsSync - fstats = fs.statSync file_path - catch - return undefined - - if fstats.size == 0 - return null - - try - content = JSON.parse(fs.readFileSync(file_path, "utf8")) - catch error - if compileStep? - compileStep.error - message: "Can't load `#{file_path}' JSON "+error.message, - sourcePath: compileStep._fullInputPath - - throw new Error "Can't load `#{file_path}' JSON" diff --git a/packages/tap-i18n/lib/plugin/helpers/load_yml.coffee b/packages/tap-i18n/lib/plugin/helpers/load_yml.coffee deleted file mode 100755 index 77f898c3398c..000000000000 --- a/packages/tap-i18n/lib/plugin/helpers/load_yml.coffee +++ /dev/null @@ -1,25 +0,0 @@ -fs = Npm.require 'fs' -YAML = Npm.require 'yamljs' - -# loads a yml from file_path -# -# returns undefined if file doesn't exist null if file is empty, parsed content otherwise -_.extend share.helpers, - loadYAML: (file_path, compileStep=null) -> - try # use try/catch to avoid the additional syscall to fs.existsSync - fstats = fs.statSync file_path - catch - return undefined - - if fstats.size == 0 - return null - - try - content = YAML.load(file_path) - catch error - if compileStep? - compileStep.error - message: "Can't load `#{file_path}' YAML", - sourcePath: compileStep._fullInputPath - - throw new Error "Can't load `#{file_path}' YAML" diff --git a/packages/tap-i18n/lib/tap_i18n/tap_i18n-client.coffee b/packages/tap-i18n/lib/tap_i18n/tap_i18n-client.coffee deleted file mode 100755 index 5437cb8859fb..000000000000 --- a/packages/tap-i18n/lib/tap_i18n/tap_i18n-client.coffee +++ /dev/null @@ -1,198 +0,0 @@ -_.extend TAPi18n.prototype, - _languageSpecificTranslators: null - _languageSpecificTranslatorsTrackers: null - - _getLanguageFilePath: (lang_tag) -> - if not @_enabled() - return null - - path = if @.conf.cdn_path? then @.conf.cdn_path else @.conf.i18n_files_route - path = path.replace /\/$/, "" - if Meteor.isCordova and path[0] == "/" - path = Meteor.absoluteUrl().replace(/\/+$/, "") + path - - "#{path}/#{lang_tag}.json" - - _loadLanguage: (languageTag) -> - # Load languageTag and its dependencies languages to TAPi18next if we - # haven't loaded them already. - # - # languageTag dependencies languages are: - # * The base language if languageTag is a dialect. - # * The fallback language (en) if we haven't loaded it already. - # - # Returns a deferred object that resolves with no arguments if all files - # loaded successfully to TAPi18next and rejects with array of error - # messages otherwise - # - # Example: - # TAPi18n._loadLanguage("pt-BR") - # .done(function () { - # console.log("languageLoaded successfully"); - # }) - # .fail(function (messages) { - # console.log("Couldn't load languageTag", messages); - # }) - # - # The above example will attempt to load pt-BR, pt and en - - dfd = new $.Deferred() - - if not @_enabled() - return dfd.reject "tap-i18n is not enabled in the project level, check tap-i18n README" - - project_languages = @_getProjectLanguages() - - if languageTag in project_languages - if languageTag not in @_loaded_languages - loadLanguageTag = => - jqXHR = $.getJSON(@_getLanguageFilePath(languageTag)) - - jqXHR.done (data) => - @_loadLangFileObject(languageTag, data) - - @_loaded_languages.push languageTag - - dfd.resolve() - - jqXHR.fail (xhr, error_code) => - dfd.reject("Couldn't load language '#{languageTag}' JSON: #{error_code}") - - directDependencyLanguageTag = if "-" in languageTag then languageTag.replace(/-.*/, "") else fallback_language - - # load dependency language if it is part of the project and not the fallback language - if languageTag != fallback_language and directDependencyLanguageTag in project_languages - dependencyLoadDfd = @_loadLanguage directDependencyLanguageTag - - dependencyLoadDfd.done => - # All dependencies loaded successfully - loadLanguageTag() - - dependencyLoadDfd.fail (message) => - dfd.reject("Loading process failed since dependency language - '#{directDependencyLanguageTag}' failed to load: " + message) - else - loadLanguageTag() - else - # languageTag loaded already - dfd.resolve() - else - dfd.reject(["Language #{languageTag} is not supported"]) - - return dfd.promise() - - _registerHelpers: (package_name, template) -> - if package_name != globals.project_translations_domain - tapI18nextProxy = @_getPackageI18nextProxy(@packages[package_name].namespace) - else - tapI18nextProxy = @_getPackageI18nextProxy(globals.project_translations_domain) - - underscore_helper = (key, args...) -> - options = (args.pop()).hash - if not _.isEmpty(args) - options.sprintf = args - - tapI18nextProxy(key, options) - - # template specific helpers - if package_name != globals.project_translations_domain - # {{_ }} - if Template[template]? and Template[template].helpers? - helpers = {} - helpers[@packages[package_name].helper_name] = underscore_helper - Template[template].helpers(helpers) - - # global helpers - else - # {{_ }} - UI.registerHelper @conf.helper_name, underscore_helper - - # {{languageTag}} - UI.registerHelper "languageTag", () => @getLanguage() - - return - - _getRegisterHelpersProxy: (package_name) -> - # A proxy to _registerHelpers where the package_name is fixed to package_name - (template) => - @_registerHelpers(package_name, template) - - _prepareLanguageSpecificTranslator: (lang_tag) -> - dfd = (new $.Deferred()).resolve().promise() - - if lang_tag of @_languageSpecificTranslatorsTrackers - return dfd - - @_languageSpecificTranslatorsTrackers[lang_tag] = new Tracker.Dependency - - if not(lang_tag of @_languageSpecificTranslators) - dfd = @_loadLanguage(lang_tag) - .done => - @_languageSpecificTranslators[lang_tag] = @_getSpecificLangTranslator(lang_tag) - - @_languageSpecificTranslatorsTrackers[lang_tag].changed() - - return dfd - - _getPackageI18nextProxy: (package_name) -> - # A proxy to TAPi18next.t where the namespace is preset to the package's - - (key, options, lang_tag=null) => - # Devs get confused and use lang option instead of lng option, make lang - # alias of lng - if options?.lang? and not options?.lng? - options.lng = options.lang - - if options?.lng? and not lang_tag? - lang_tag = options.lng - # Remove options.lng so we won't pass it to the regular TAPi18next - # before the language specific translator is ready to keep behavior - # consistent. - # - # If lang is actually ready before the language specifc translator is - # ready, TAPi18next will translate to lang_tag if we won't remove - # options.lng. - delete options.lng - - if lang_tag? - @_prepareLanguageSpecificTranslator(lang_tag) - - @_languageSpecificTranslatorsTrackers[lang_tag].depend() - - if lang_tag of @_languageSpecificTranslators - return @_languageSpecificTranslators[lang_tag] "#{TAPi18n._getPackageDomain(package_name)}:#{key}", options - else - return TAPi18next.t "#{TAPi18n._getPackageDomain(package_name)}:#{key}", options - - # If inside a reactive computation, we want to invalidate the computation if the client lang changes - @_language_changed_tracker.depend() - - - TAPi18next.t "#{TAPi18n._getPackageDomain(package_name)}:#{key}", options - - _onceEnabled: () -> - @_registerHelpers globals.project_translations_domain - - _abortPreviousSetLang: null - setLanguage: (lang_tag) -> - self = @ - - @_abortPreviousSetLang?() - - isAborted = false - @_abortPreviousSetLang = -> isAborted = true - - @_loadLanguage(lang_tag).then => - if not isAborted - TAPi18next.setLng(lang_tag) - - @_language_changed_tracker.changed() - Session.set @_loaded_lang_session_key, lang_tag - - getLanguage: -> - if not @._enabled() - return null - - session_lang = Session.get @_loaded_lang_session_key - - if session_lang? then session_lang else @._fallback_language diff --git a/packages/tap-i18n/lib/tap_i18n/tap_i18n-common.coffee b/packages/tap-i18n/lib/tap_i18n/tap_i18n-common.coffee deleted file mode 100755 index 23bc6e59f84c..000000000000 --- a/packages/tap-i18n/lib/tap_i18n/tap_i18n-common.coffee +++ /dev/null @@ -1,143 +0,0 @@ -fallback_language = globals.fallback_language - -TAPi18n = -> - EventEmitter.call @ - - @_fallback_language = fallback_language - - @_language_changed_tracker = new Tracker.Dependency - - @_loaded_languages = [fallback_language] # stores the loaded languages, the fallback language is loaded automatically - - @conf = null # If conf isn't null we assume that tap:i18n is enabled for the project. - # We assume conf is valid, we sterilize and validate it during the build process. - - @packages = {} # Stores the packages' package-tap.i18n jsons - - @languages_names = {} # Stores languages that we've found languages files for in the project dir. - # format: - # { - # lang_tag: [lang_name_in_english, lang_name_in_local_language] - # } - - @translations = {} # Stores the packages/project translations - Server side only - # fallback_language translations are not stored here - - - if Meteor.isClient - Session.set @_loaded_lang_session_key, null - - @_languageSpecificTranslators = {} - @_languageSpecificTranslatorsTrackers = {} - - if Meteor.isServer - @server_translators = {} - - Meteor.startup => - # If tap-i18n is enabled for that project - if @_enabled() - @_registerHTTPMethod() - - @__ = @_getPackageI18nextProxy(globals.project_translations_domain) - - TAPi18next.setLng fallback_language - - return @ - -Util.inherits TAPi18n, EventEmitter - -_.extend TAPi18n.prototype, - _loaded_lang_session_key: "TAPi18n::loaded_lang" - - _enable: (conf) -> - # tap:i18n gets enabled for a project once a conf file is set for it. - # It can be either a conf object that was set by project-tap.i18n file or - # a default conf, which is being added if the project has lang files - # (*.i18n.json) but not project-tap.i18n - @conf = conf - - @._onceEnabled() - - _onceEnabled: () -> - # The arch specific code can use this for procedures that should be performed once - # tap:i18n gets enabled (project conf file is being set) - return - - _enabled: -> - # read the comment of @conf - @conf? - - _getPackageDomain: (package_name) -> - package_name.replace(/:/g, "-") - - addResourceBundle: (lang_tag, package_name, translations) -> - TAPi18next.addResourceBundle(lang_tag, @_getPackageDomain(package_name), translations) - - _getSpecificLangTranslator: (lang) -> - current_lang = TAPi18next.lng() - - translator = null - TAPi18next.setLng lang, {fixLng: true}, (lang_translator) => - translator = lang_translator - - # Restore i18next lang that had been changed in the process of generating - # lang specific translator - TAPi18next.setLng current_lang - - return translator - - _getProjectLanguages: () -> - # Return an array of languages available for the current project - if @._enabled() - if _.isArray @.conf.supported_languages - return _.union([@._fallback_language], @.conf.supported_languages) - else - # If supported_languages is null, all the languages we found - # translations files to in the project level are considered supported. - # We use the @.languages_names array to tell which languages we found - # since for every i18n.json file we found in the project level we add - # an entry for its language to @.languages_names in the build process. - # - # We also know for certain that when tap-i18n is enabled the fallback - # lang is in @.languages_names - return _.keys @.languages_names - else - return [@._fallback_language] - - getLanguages: -> - if not @._enabled() - return null - - languages = {} - for lang_tag in @._getProjectLanguages() - languages[lang_tag] = - name: @.languages_names[lang_tag][1] - en: @.languages_names[lang_tag][0] - - languages - - _loadLangFileObject: (language_tag, data) -> - for package_name, package_keys of data - # Translations that are added by loadTranslations() have higher priority - package_keys = _.extend({}, package_keys, @_loadTranslations_cache[language_tag]?[package_name] or {}) - - @addResourceBundle(language_tag, package_name, package_keys) - - _loadTranslations_cache: {} - loadTranslations: (translations, namespace) -> - project_languages = @_getProjectLanguages() - - for language_tag, translation_keys of translations - if not @_loadTranslations_cache[language_tag]? - @_loadTranslations_cache[language_tag] = {} - - if not @_loadTranslations_cache[language_tag][namespace]? - @_loadTranslations_cache[language_tag][namespace] = {} - - _.extend(@_loadTranslations_cache[language_tag][namespace], translation_keys) - - @addResourceBundle(language_tag, namespace, translation_keys) - - if Meteor.isClient and @getLanguage() == language_tag - # Retranslate if session language updated - @_language_changed_tracker.changed() \ No newline at end of file diff --git a/packages/tap-i18n/lib/tap_i18n/tap_i18n-helpers.coffee b/packages/tap-i18n/lib/tap_i18n/tap_i18n-helpers.coffee deleted file mode 100755 index 74aff3ad7007..000000000000 --- a/packages/tap-i18n/lib/tap_i18n/tap_i18n-helpers.coffee +++ /dev/null @@ -1 +0,0 @@ -share.helpers = {} \ No newline at end of file diff --git a/packages/tap-i18n/lib/tap_i18n/tap_i18n-init.coffee b/packages/tap-i18n/lib/tap_i18n/tap_i18n-init.coffee deleted file mode 100755 index f51365a4e7a0..000000000000 --- a/packages/tap-i18n/lib/tap_i18n/tap_i18n-init.coffee +++ /dev/null @@ -1 +0,0 @@ -TAPi18n = new TAPi18n() \ No newline at end of file diff --git a/packages/tap-i18n/lib/tap_i18n/tap_i18n-server.coffee b/packages/tap-i18n/lib/tap_i18n/tap_i18n-server.coffee deleted file mode 100755 index 014e89d0d4c5..000000000000 --- a/packages/tap-i18n/lib/tap_i18n/tap_i18n-server.coffee +++ /dev/null @@ -1,85 +0,0 @@ -_.extend TAPi18n.prototype, - server_translators: null - - _registerServerTranslator: (lang_tag, package_name) -> - if @_enabled() - if not(lang_tag of @server_translators) - @server_translators[lang_tag] = @_getSpecificLangTranslator(lang_tag) - - # fallback language is integrated, and isn't part of @translations - if lang_tag != @_fallback_language - @addResourceBundle(lang_tag, package_name, @translations[lang_tag][package_name]) - - if not(@_fallback_language of @server_translators) - @server_translators[@_fallback_language] = @_getSpecificLangTranslator(@_fallback_language) - - _registerAllServerTranslators: () -> - for lang_tag in @_getProjectLanguages() - for package_name of @translations[lang_tag] - @_registerServerTranslator(lang_tag, package_name) - - _getPackageI18nextProxy: (package_name) -> - # A proxy to TAPi18next.t where the namespace is preset to the package's - (key, options, lang_tag=null) => - if not lang_tag? - # translate to fallback_language - return @server_translators[@_fallback_language] "#{@_getPackageDomain(package_name)}:#{key}", options - else if not(lang_tag of @server_translators) - console.log "Warning: language #{lang_tag} is not supported in this project, fallback language (#{@_fallback_language})" - return @server_translators[@_fallback_language] "#{@_getPackageDomain(package_name)}:#{key}", options - else - return @server_translators[lang_tag] "#{@_getPackageDomain(package_name)}:#{key}", options - - _registerHTTPMethod: -> - self = @ - - methods = {} - - if not self._enabled() - throw new Meteor.Error 500, "tap-i18n has to be enabled in order to register the HTTP method" - - methods["#{self.conf.i18n_files_route.replace(/\/$/, "")}/multi/:langs"] = - get: () -> - if not RegExp("^((#{globals.langauges_tags_regex},)*#{globals.langauges_tags_regex}|all).json$").test(@params.langs) - return @setStatusCode(401) - - langs = @params.langs.replace ".json", "" - - if langs == "all" - output = self.translations - else - output = {} - - langs = langs.split(",") - for lang_tag in langs - if lang_tag in self._getProjectLanguages() and \ - lang_tag != self._fallback_language # fallback language is integrated to the bundle - language_translations = self.translations[lang_tag] - - if language_translations? - output[lang_tag] = language_translations - - return JSON.stringify(output) - - methods["#{self.conf.i18n_files_route.replace(/\/$/, "")}/:lang"] = - get: () -> - if not RegExp("^#{globals.langauges_tags_regex}.json$").test(@params.lang) - return @setStatusCode(401) - - lang_tag = @params.lang.replace ".json", "" - - if lang_tag not in self._getProjectLanguages() or \ - lang_tag == self._fallback_language # fallback language is integrated to the bundle - return @setStatusCode(404) # not found - - language_translations = self.translations[lang_tag] - # returning {} if lang_tag is not in translations allows the project - # developer to force a language supporte with project-tap.i18n's - # supported_languages property, even if that language has no lang - # files. - return JSON.stringify(if language_translations? then language_translations else {}) - - HTTP.methods methods - - _onceEnabled: -> - @_registerAllServerTranslators() \ No newline at end of file diff --git a/packages/tap-i18n/lib/tap_i18next/tap_i18next-1.7.3.js b/packages/tap-i18n/lib/tap_i18next/tap_i18next-1.7.3.js deleted file mode 100755 index dbf4f810bd68..000000000000 --- a/packages/tap-i18n/lib/tap_i18next/tap_i18next-1.7.3.js +++ /dev/null @@ -1,2748 +0,0 @@ -// tap_i18next is a copy of i18next that expose i18next to the global namespace -// under the name name TAPi18next instead of i18n to (1) avoid interfering with other -// Meteor packages that might use i18n with different configurations than we do -// or worse - (2) using a different version of i18next -// -// setJqueryExt is disabled by default in TAPi18next -// sprintf is a default postProcess in TAPi18next -// -// TAPi18next is set outside of the singleton builder to make it available in the -// package level - -// i18next, v1.7.3 -// Copyright (c)2014 Jan Mühlemann (jamuhl). -// Distributed under MIT license -// http://i18next.com - -// set TAPi18next outside of the singleton builder to make it available in the package level -TAPi18next = {}; -(function() { - - // add indexOf to non ECMA-262 standard compliant browsers - if (!Array.prototype.indexOf) { - Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { - "use strict"; - if (this == null) { - throw new TypeError(); - } - var t = Object(this); - var len = t.length >>> 0; - if (len === 0) { - return -1; - } - var n = 0; - if (arguments.length > 0) { - n = Number(arguments[1]); - if (n != n) { // shortcut for verifying if it's NaN - n = 0; - } else if (n != 0 && n != Infinity && n != -Infinity) { - n = (n > 0 || -1) * Math.floor(Math.abs(n)); - } - } - if (n >= len) { - return -1; - } - var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); - for (; k < len; k++) { - if (k in t && t[k] === searchElement) { - return k; - } - } - return -1; - } - } - - // add lastIndexOf to non ECMA-262 standard compliant browsers - if (!Array.prototype.lastIndexOf) { - Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/) { - "use strict"; - if (this == null) { - throw new TypeError(); - } - var t = Object(this); - var len = t.length >>> 0; - if (len === 0) { - return -1; - } - var n = len; - if (arguments.length > 1) { - n = Number(arguments[1]); - if (n != n) { - n = 0; - } else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) { - n = (n > 0 || -1) * Math.floor(Math.abs(n)); - } - } - var k = n >= 0 ? Math.min(n, len - 1) : len - Math.abs(n); - for (; k >= 0; k--) { - if (k in t && t[k] === searchElement) { - return k; - } - } - return -1; - }; - } - - // Add string trim for IE8. - if (typeof String.prototype.trim !== 'function') { - String.prototype.trim = function() { - return this.replace(/^\s+|\s+$/g, ''); - } - } - - var root = this - , $ = root.jQuery || root.Zepto - , resStore = {} - , currentLng - , replacementCounter = 0 - , languages = [] - , initialized = false; - - - // Export the i18next object for **CommonJS**. - // If we're not in CommonJS, add `i18n` to the - // global object or to jquery. - if (typeof module !== 'undefined' && module.exports) { - module.exports = TAPi18next; - } else { - if ($) { - $.TAPi18next = $.TAPi18next || TAPi18next; - } - - root.TAPi18next = root.TAPi18next || TAPi18next; - } - // defaults - var o = { - lng: undefined, - load: 'all', - preload: [], - lowerCaseLng: false, - returnObjectTrees: false, - fallbackLng: ['dev'], - fallbackNS: [], - detectLngQS: 'setLng', - ns: 'translation', - fallbackOnNull: true, - fallbackOnEmpty: false, - fallbackToDefaultNS: false, - nsseparator: ':', - keyseparator: '.', - selectorAttr: 'data-i18n', - debug: false, - - resGetPath: 'locales/__lng__/__ns__.json', - resPostPath: 'locales/add/__lng__/__ns__', - - getAsync: true, - postAsync: true, - - resStore: undefined, - useLocalStorage: false, - localStorageExpirationTime: 7*24*60*60*1000, - - dynamicLoad: false, - sendMissing: false, - sendMissingTo: 'fallback', // current | all - sendType: 'POST', - - interpolationPrefix: '__', - interpolationSuffix: '__', - reusePrefix: '$t(', - reuseSuffix: ')', - pluralSuffix: '_plural', - pluralNotFound: ['plural_not_found', Math.random()].join(''), - contextNotFound: ['context_not_found', Math.random()].join(''), - escapeInterpolation: false, - - setJqueryExt: false, - defaultValueFromContent: true, - useDataAttrOptions: false, - cookieExpirationTime: undefined, - useCookie: true, - cookieName: 'TAPi18next', - cookieDomain: undefined, - - objectTreeKeyHandler: undefined, - postProcess: ["sprintf"], - parseMissingKey: undefined, - - shortcutFunction: 'sprintf' // or: defaultValue - }; - function _extend(target, source) { - if (!source || typeof source === 'function') { - return target; - } - - for (var attr in source) { target[attr] = source[attr]; } - return target; - } - - function _each(object, callback, args) { - var name, i = 0, - length = object.length, - isObj = length === undefined || Object.prototype.toString.apply(object) !== '[object Array]' || typeof object === "function"; - - if (args) { - if (isObj) { - for (name in object) { - if (callback.apply(object[name], args) === false) { - break; - } - } - } else { - for ( ; i < length; ) { - if (callback.apply(object[i++], args) === false) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if (isObj) { - for (name in object) { - if (callback.call(object[name], name, object[name]) === false) { - break; - } - } - } else { - for ( ; i < length; ) { - if (callback.call(object[i], i, object[i++]) === false) { - break; - } - } - } - } - - return object; - } - - var _entityMap = { - "&": "&", - "<": "<", - ">": ">", - '"': '"', - "'": ''', - "/": '/' - }; - - function _escape(data) { - if (typeof data === 'string') { - return data.replace(/[&<>"'\/]/g, function (s) { - return _entityMap[s]; - }); - }else{ - return data; - } - } - - function _ajax(options) { - - // v0.5.0 of https://github.com/goloroden/http.js - var getXhr = function (callback) { - // Use the native XHR object if the browser supports it. - if (window.XMLHttpRequest) { - return callback(null, new XMLHttpRequest()); - } else if (window.ActiveXObject) { - // In Internet Explorer check for ActiveX versions of the XHR object. - try { - return callback(null, new ActiveXObject("Msxml2.XMLHTTP")); - } catch (e) { - return callback(null, new ActiveXObject("Microsoft.XMLHTTP")); - } - } - - // If no XHR support was found, throw an error. - return callback(new Error()); - }; - - var encodeUsingUrlEncoding = function (data) { - if(typeof data === 'string') { - return data; - } - - var result = []; - for(var dataItem in data) { - if(data.hasOwnProperty(dataItem)) { - result.push(encodeURIComponent(dataItem) + '=' + encodeURIComponent(data[dataItem])); - } - } - - return result.join('&'); - }; - - var utf8 = function (text) { - text = text.replace(/\r\n/g, '\n'); - var result = ''; - - for(var i = 0; i < text.length; i++) { - var c = text.charCodeAt(i); - - if(c < 128) { - result += String.fromCharCode(c); - } else if((c > 127) && (c < 2048)) { - result += String.fromCharCode((c >> 6) | 192); - result += String.fromCharCode((c & 63) | 128); - } else { - result += String.fromCharCode((c >> 12) | 224); - result += String.fromCharCode(((c >> 6) & 63) | 128); - result += String.fromCharCode((c & 63) | 128); - } - } - - return result; - }; - - var base64 = function (text) { - var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; - - text = utf8(text); - var result = '', - chr1, chr2, chr3, - enc1, enc2, enc3, enc4, - i = 0; - - do { - chr1 = text.charCodeAt(i++); - chr2 = text.charCodeAt(i++); - chr3 = text.charCodeAt(i++); - - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if(isNaN(chr2)) { - enc3 = enc4 = 64; - } else if(isNaN(chr3)) { - enc4 = 64; - } - - result += - keyStr.charAt(enc1) + - keyStr.charAt(enc2) + - keyStr.charAt(enc3) + - keyStr.charAt(enc4); - chr1 = chr2 = chr3 = ''; - enc1 = enc2 = enc3 = enc4 = ''; - } while(i < text.length); - - return result; - }; - - var mergeHeaders = function () { - // Use the first header object as base. - var result = arguments[0]; - - // Iterate through the remaining header objects and add them. - for(var i = 1; i < arguments.length; i++) { - var currentHeaders = arguments[i]; - for(var header in currentHeaders) { - if(currentHeaders.hasOwnProperty(header)) { - result[header] = currentHeaders[header]; - } - } - } - - // Return the merged headers. - return result; - }; - - var ajax = function (method, url, options, callback) { - // Adjust parameters. - if(typeof options === 'function') { - callback = options; - options = {}; - } - - // Set default parameter values. - options.cache = options.cache || false; - options.data = options.data || {}; - options.headers = options.headers || {}; - options.jsonp = options.jsonp || false; - options.async = options.async === undefined ? true : options.async; - - // Merge the various header objects. - var headers = mergeHeaders({ - 'accept': '*/*', - 'content-type': 'application/x-www-form-urlencoded;charset=UTF-8' - }, ajax.headers, options.headers); - - // Encode the data according to the content-type. - var payload; - if (headers['content-type'] === 'application/json') { - payload = JSON.stringify(options.data); - } else { - payload = encodeUsingUrlEncoding(options.data); - } - - // Specially prepare GET requests: Setup the query string, handle caching and make a JSONP call - // if neccessary. - if(method === 'GET') { - // Setup the query string. - var queryString = []; - if(payload) { - queryString.push(payload); - payload = null; - } - - // Handle caching. - if(!options.cache) { - queryString.push('_=' + (new Date()).getTime()); - } - - // If neccessary prepare the query string for a JSONP call. - if(options.jsonp) { - queryString.push('callback=' + options.jsonp); - queryString.push('jsonp=' + options.jsonp); - } - - // Merge the query string and attach it to the url. - queryString = queryString.join('&'); - if (queryString.length > 1) { - if (url.indexOf('?') > -1) { - url += '&' + queryString; - } else { - url += '?' + queryString; - } - } - - // Make a JSONP call if neccessary. - if(options.jsonp) { - var head = document.getElementsByTagName('head')[0]; - var script = document.createElement('script'); - script.type = 'text/javascript'; - script.src = url; - head.appendChild(script); - return; - } - } - - // Since we got here, it is no JSONP request, so make a normal XHR request. - getXhr(function (err, xhr) { - if(err) return callback(err); - - // Open the request. - xhr.open(method, url, options.async); - - // Set the request headers. - for(var header in headers) { - if(headers.hasOwnProperty(header)) { - xhr.setRequestHeader(header, headers[header]); - } - } - - // Handle the request events. - xhr.onreadystatechange = function () { - if(xhr.readyState === 4) { - var data = xhr.responseText || ''; - - // If no callback is given, return. - if(!callback) { - return; - } - - // Return an object that provides access to the data as text and JSON. - callback(xhr.status, { - text: function () { - return data; - }, - - json: function () { - return JSON.parse(data); - } - }); - } - }; - - // Actually send the XHR request. - xhr.send(payload); - }); - }; - - // Define the external interface. - var http = { - authBasic: function (username, password) { - ajax.headers['Authorization'] = 'Basic ' + base64(username + ':' + password); - }, - - connect: function (url, options, callback) { - return ajax('CONNECT', url, options, callback); - }, - - del: function (url, options, callback) { - return ajax('DELETE', url, options, callback); - }, - - get: function (url, options, callback) { - return ajax('GET', url, options, callback); - }, - - head: function (url, options, callback) { - return ajax('HEAD', url, options, callback); - }, - - headers: function (headers) { - ajax.headers = headers || {}; - }, - - isAllowed: function (url, verb, callback) { - this.options(url, function (status, data) { - callback(data.text().indexOf(verb) !== -1); - }); - }, - - options: function (url, options, callback) { - return ajax('OPTIONS', url, options, callback); - }, - - patch: function (url, options, callback) { - return ajax('PATCH', url, options, callback); - }, - - post: function (url, options, callback) { - return ajax('POST', url, options, callback); - }, - - put: function (url, options, callback) { - return ajax('PUT', url, options, callback); - }, - - trace: function (url, options, callback) { - return ajax('TRACE', url, options, callback); - } - }; - - - var methode = options.type ? options.type.toLowerCase() : 'get'; - - http[methode](options.url, options, function (status, data) { - if (status === 200) { - options.success(data.json(), status, null); - } else { - options.error(data.text(), status, null); - } - }); - } - - var _cookie = { - create: function(name,value,minutes,domain) { - var expires; - if (minutes) { - var date = new Date(); - date.setTime(date.getTime()+(minutes*60*1000)); - expires = "; expires="+date.toGMTString(); - } - else expires = ""; - domain = (domain)? "domain="+domain+";" : ""; - document.cookie = name+"="+value+expires+";"+domain+"path=/"; - }, - - read: function(name) { - var nameEQ = name + "="; - var ca = document.cookie.split(';'); - for(var i=0;i < ca.length;i++) { - var c = ca[i]; - while (c.charAt(0)==' ') c = c.substring(1,c.length); - if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length,c.length); - } - return null; - }, - - remove: function(name) { - this.create(name,"",-1); - } - }; - - var cookie_noop = { - create: function(name,value,minutes,domain) {}, - read: function(name) { return null; }, - remove: function(name) {} - }; - - - - // move dependent functions to a container so that - // they can be overriden easier in no jquery environment (node.js) - var f = { - extend: $ ? $.extend : _extend, - each: $ ? $.each : _each, - ajax: $ ? $.ajax : (typeof document !== 'undefined' ? _ajax : function() {}), - cookie: typeof document !== 'undefined' ? _cookie : cookie_noop, - detectLanguage: detectLanguage, - escape: _escape, - log: function(str) { - if (o.debug && typeof console !== "undefined") console.log(str); - }, - toLanguages: function(lng) { - var languages = []; - if (typeof lng === 'string' && lng.indexOf('-') > -1) { - var parts = lng.split('-'); - - lng = o.lowerCaseLng ? - parts[0].toLowerCase() + '-' + parts[1].toLowerCase() : - parts[0].toLowerCase() + '-' + parts[1].toUpperCase(); - - if (o.load !== 'unspecific') languages.push(lng); - if (o.load !== 'current') languages.push(parts[0]); - } else { - languages.push(lng); - } - - for (var i = 0; i < o.fallbackLng.length; i++) { - if (languages.indexOf(o.fallbackLng[i]) === -1 && o.fallbackLng[i]) languages.push(o.fallbackLng[i]); - } - - return languages; - }, - regexEscape: function(str) { - return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); - } - }; - function init(options, cb) { - - if (typeof options === 'function') { - cb = options; - options = {}; - } - options = options || {}; - - // override defaults with passed in options - f.extend(o, options); - delete o.fixLng; /* passed in each time */ - - // create namespace object if namespace is passed in as string - if (typeof o.ns == 'string') { - o.ns = { namespaces: [o.ns], defaultNs: o.ns}; - } - - // fallback namespaces - if (typeof o.fallbackNS == 'string') { - o.fallbackNS = [o.fallbackNS]; - } - - // fallback languages - if (typeof o.fallbackLng == 'string' || typeof o.fallbackLng == 'boolean') { - o.fallbackLng = [o.fallbackLng]; - } - - // escape prefix/suffix - o.interpolationPrefixEscaped = f.regexEscape(o.interpolationPrefix); - o.interpolationSuffixEscaped = f.regexEscape(o.interpolationSuffix); - - if (!o.lng) o.lng = f.detectLanguage(); - if (o.lng) { - // set cookie with lng set (as detectLanguage will set cookie on need) - if (o.useCookie) f.cookie.create(o.cookieName, o.lng, o.cookieExpirationTime, o.cookieDomain); - } else { - o.lng = o.fallbackLng[0]; - if (o.useCookie) f.cookie.remove(o.cookieName); - } - - languages = f.toLanguages(o.lng); - currentLng = languages[0]; - f.log('currentLng set to: ' + currentLng); - - var lngTranslate = translate; - if (options.fixLng) { - lngTranslate = function(key, options) { - options = options || {}; - options.lng = options.lng || lngTranslate.lng; - return translate(key, options); - }; - lngTranslate.lng = currentLng; - } - - pluralExtensions.setCurrentLng(currentLng); - - // add JQuery extensions - if ($ && o.setJqueryExt) addJqueryFunct(); - - // jQuery deferred - var deferred; - if ($ && $.Deferred) { - deferred = $.Deferred(); - } - - // return immidiatly if res are passed in - if (o.resStore) { - resStore = o.resStore; - initialized = true; - if (cb) cb(lngTranslate); - if (deferred) deferred.resolve(lngTranslate); - if (deferred) return deferred.promise(); - return; - } - - // languages to load - var lngsToLoad = f.toLanguages(o.lng); - if (typeof o.preload === 'string') o.preload = [o.preload]; - for (var i = 0, l = o.preload.length; i < l; i++) { - var pres = f.toLanguages(o.preload[i]); - for (var y = 0, len = pres.length; y < len; y++) { - if (lngsToLoad.indexOf(pres[y]) < 0) { - lngsToLoad.push(pres[y]); - } - } - } - - // else load them - TAPi18next.sync.load(lngsToLoad, o, function(err, store) { - resStore = store; - initialized = true; - - if (cb) cb(lngTranslate); - if (deferred) deferred.resolve(lngTranslate); - }); - - if (deferred) return deferred.promise(); - } - function preload(lngs, cb) { - if (typeof lngs === 'string') lngs = [lngs]; - for (var i = 0, l = lngs.length; i < l; i++) { - if (o.preload.indexOf(lngs[i]) < 0) { - o.preload.push(lngs[i]); - } - } - return init(cb); - } - - function addResourceBundle(lng, ns, resources) { - if (typeof ns !== 'string') { - resources = ns; - ns = o.ns.defaultNs; - } else if (o.ns.namespaces.indexOf(ns) < 0) { - o.ns.namespaces.push(ns); - } - - resStore[lng] = resStore[lng] || {}; - resStore[lng][ns] = resStore[lng][ns] || {}; - - f.extend(resStore[lng][ns], resources); - } - - function removeResourceBundle(lng, ns) { - if (typeof ns !== 'string') { - ns = o.ns.defaultNs; - } - - resStore[lng] = resStore[lng] || {}; - resStore[lng][ns] = {}; - } - - function setDefaultNamespace(ns) { - o.ns.defaultNs = ns; - } - - function loadNamespace(namespace, cb) { - loadNamespaces([namespace], cb); - } - - function loadNamespaces(namespaces, cb) { - var opts = { - dynamicLoad: o.dynamicLoad, - resGetPath: o.resGetPath, - getAsync: o.getAsync, - customLoad: o.customLoad, - ns: { namespaces: namespaces, defaultNs: ''} /* new namespaces to load */ - }; - - // languages to load - var lngsToLoad = f.toLanguages(o.lng); - if (typeof o.preload === 'string') o.preload = [o.preload]; - for (var i = 0, l = o.preload.length; i < l; i++) { - var pres = f.toLanguages(o.preload[i]); - for (var y = 0, len = pres.length; y < len; y++) { - if (lngsToLoad.indexOf(pres[y]) < 0) { - lngsToLoad.push(pres[y]); - } - } - } - - // check if we have to load - var lngNeedLoad = []; - for (var a = 0, lenA = lngsToLoad.length; a < lenA; a++) { - var needLoad = false; - var resSet = resStore[lngsToLoad[a]]; - if (resSet) { - for (var b = 0, lenB = namespaces.length; b < lenB; b++) { - if (!resSet[namespaces[b]]) needLoad = true; - } - } else { - needLoad = true; - } - - if (needLoad) lngNeedLoad.push(lngsToLoad[a]); - } - - if (lngNeedLoad.length) { - TAPi18next.sync._fetch(lngNeedLoad, opts, function(err, store) { - var todo = namespaces.length * lngNeedLoad.length; - - // load each file individual - f.each(namespaces, function(nsIndex, nsValue) { - - // append namespace to namespace array - if (o.ns.namespaces.indexOf(nsValue) < 0) { - o.ns.namespaces.push(nsValue); - } - - f.each(lngNeedLoad, function(lngIndex, lngValue) { - resStore[lngValue] = resStore[lngValue] || {}; - resStore[lngValue][nsValue] = store[lngValue][nsValue]; - - todo--; // wait for all done befor callback - if (todo === 0 && cb) { - if (o.useLocalStorage) TAPi18next.sync._storeLocal(resStore); - cb(); - } - }); - }); - }); - } else { - if (cb) cb(); - } - } - - function setLng(lng, options, cb) { - if (typeof options === 'function') { - cb = options; - options = {}; - } else if (!options) { - options = {}; - } - - options.lng = lng; - return init(options, cb); - } - - function lng() { - return currentLng; - } - function addJqueryFunct() { - // $.t shortcut - $.t = $.t || translate; - - function parse(ele, key, options) { - if (key.length === 0) return; - - var attr = 'text'; - - if (key.indexOf('[') === 0) { - var parts = key.split(']'); - key = parts[1]; - attr = parts[0].substr(1, parts[0].length-1); - } - - if (key.indexOf(';') === key.length-1) { - key = key.substr(0, key.length-2); - } - - var optionsToUse; - if (attr === 'html') { - optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options; - ele.html($.t(key, optionsToUse)); - } else if (attr === 'text') { - optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.text() }, options) : options; - ele.text($.t(key, optionsToUse)); - } else if (attr === 'prepend') { - optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options; - ele.prepend($.t(key, optionsToUse)); - } else if (attr === 'append') { - optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options; - ele.append($.t(key, optionsToUse)); - } else if (attr.indexOf("data-") === 0) { - var dataAttr = attr.substr(("data-").length); - optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.data(dataAttr) }, options) : options; - var translated = $.t(key, optionsToUse); - //we change into the data cache - ele.data(dataAttr, translated); - //we change into the dom - ele.attr(attr, translated); - } else { - optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.attr(attr) }, options) : options; - ele.attr(attr, $.t(key, optionsToUse)); - } - } - - function localize(ele, options) { - var key = ele.attr(o.selectorAttr); - if (!key && typeof key !== 'undefined' && key !== false) key = ele.text() || ele.val(); - if (!key) return; - - var target = ele - , targetSelector = ele.data("i18n-target"); - if (targetSelector) { - target = ele.find(targetSelector) || ele; - } - - if (!options && o.useDataAttrOptions === true) { - options = ele.data("i18n-options"); - } - options = options || {}; - - if (key.indexOf(';') >= 0) { - var keys = key.split(';'); - - $.each(keys, function(m, k) { - if (k !== '') parse(target, k, options); - }); - - } else { - parse(target, key, options); - } - - if (o.useDataAttrOptions === true) ele.data("i18n-options", options); - } - - // fn - $.fn.TAPi18next = function (options) { - return this.each(function() { - // localize element itself - localize($(this), options); - - // localize childs - var elements = $(this).find('[' + o.selectorAttr + ']'); - elements.each(function() { - localize($(this), options); - }); - }); - }; - } - function applyReplacement(str, replacementHash, nestedKey, options) { - if (!str) return str; - - options = options || replacementHash; // first call uses replacement hash combined with options - if (str.indexOf(options.interpolationPrefix || o.interpolationPrefix) < 0) return str; - - var prefix = options.interpolationPrefix ? f.regexEscape(options.interpolationPrefix) : o.interpolationPrefixEscaped - , suffix = options.interpolationSuffix ? f.regexEscape(options.interpolationSuffix) : o.interpolationSuffixEscaped - , unEscapingSuffix = 'HTML'+suffix; - - f.each(replacementHash, function(key, value) { - var nextKey = nestedKey ? nestedKey + o.keyseparator + key : key; - if (typeof value === 'object' && value !== null) { - str = applyReplacement(str, value, nextKey, options); - } else { - if (options.escapeInterpolation || o.escapeInterpolation) { - str = str.replace(new RegExp([prefix, nextKey, unEscapingSuffix].join(''), 'g'), value); - str = str.replace(new RegExp([prefix, nextKey, suffix].join(''), 'g'), f.escape(value)); - } else { - str = str.replace(new RegExp([prefix, nextKey, suffix].join(''), 'g'), value); - } - // str = options.escapeInterpolation; - } - }); - return str; - } - - // append it to functions - f.applyReplacement = applyReplacement; - - function applyReuse(translated, options) { - var comma = ','; - var options_open = '{'; - var options_close = '}'; - - var opts = f.extend({}, options); - delete opts.postProcess; - - while (translated.indexOf(o.reusePrefix) != -1) { - replacementCounter++; - if (replacementCounter > o.maxRecursion) { break; } // safety net for too much recursion - var index_of_opening = translated.lastIndexOf(o.reusePrefix); - var index_of_end_of_closing = translated.indexOf(o.reuseSuffix, index_of_opening) + o.reuseSuffix.length; - var token = translated.substring(index_of_opening, index_of_end_of_closing); - var token_without_symbols = token.replace(o.reusePrefix, '').replace(o.reuseSuffix, ''); - - - if (token_without_symbols.indexOf(comma) != -1) { - var index_of_token_end_of_closing = token_without_symbols.indexOf(comma); - if (token_without_symbols.indexOf(options_open, index_of_token_end_of_closing) != -1 && token_without_symbols.indexOf(options_close, index_of_token_end_of_closing) != -1) { - var index_of_opts_opening = token_without_symbols.indexOf(options_open, index_of_token_end_of_closing); - var index_of_opts_end_of_closing = token_without_symbols.indexOf(options_close, index_of_opts_opening) + options_close.length; - try { - opts = f.extend(opts, JSON.parse(token_without_symbols.substring(index_of_opts_opening, index_of_opts_end_of_closing))); - token_without_symbols = token_without_symbols.substring(0, index_of_token_end_of_closing); - } catch (e) { - } - } - } - - var translated_token = _translate(token_without_symbols, opts); - translated = translated.replace(token, translated_token); - } - return translated; - } - - function hasContext(options) { - return (options.context && (typeof options.context == 'string' || typeof options.context == 'number')); - } - - function needsPlural(options) { - return (options.count !== undefined && typeof options.count != 'string' && options.count !== 1); - } - - function exists(key, options) { - options = options || {}; - - var notFound = _getDefaultValue(key, options) - , found = _find(key, options); - - return found !== undefined || found === notFound; - } - - function translate(key, options) { - if (typeof options === 'undefined') { - options = {}; - } - - if (!initialized) { - f.log('i18next not finished initialization. you might have called t function before loading resources finished.') - return options.defaultValue || ''; - }; - replacementCounter = 0; - return _translate.apply(null, arguments); - } - - function _getDefaultValue(key, options) { - return (options.defaultValue !== undefined) ? options.defaultValue : key; - } - - function _injectSprintfProcessor() { - - var values = []; - - // mh: build array from second argument onwards - for (var i = 1; i < arguments.length; i++) { - values.push(arguments[i]); - } - - return { - postProcess: 'sprintf', - sprintf: values - }; - } - - function _translate(potentialKeys, options) { - if (typeof options !== "undefined" && options !== null && typeof options !== 'object') { - if (o.shortcutFunction === 'sprintf') { - // mh: gettext like sprintf syntax found, automatically create sprintf processor - options = _injectSprintfProcessor.apply(null, arguments); - } else if (o.shortcutFunction === 'defaultValue') { - options = { - defaultValue: options - } - } - } else { - options = options || {}; - } - - if (potentialKeys === undefined || potentialKeys === null) return ''; - - if (typeof potentialKeys == 'string') { - potentialKeys = [potentialKeys]; - } - - var key = potentialKeys[0]; - - if (potentialKeys.length > 1) { - for (var i = 0; i < potentialKeys.length; i++) { - key = potentialKeys[i]; - if (exists(key, options)) { - break; - } - } - } - - var notFound = _getDefaultValue(key, options) - , found = _find(key, options) - , lngs = options.lng ? f.toLanguages(options.lng) : languages - , ns = options.ns || o.ns.defaultNs - , parts; - - // split ns and key - if (key.indexOf(o.nsseparator) > -1) { - parts = key.split(o.nsseparator); - ns = parts[0]; - key = parts[1]; - } - - if (found === undefined && o.sendMissing) { - if (options.lng) { - sync.postMissing(lngs[0], ns, key, notFound, lngs); - } else { - sync.postMissing(o.lng, ns, key, notFound, lngs); - } - } - - var postProcessor = options.postProcess || o.postProcess; - if (found !== undefined && postProcessor) { - if (postProcessors[postProcessor]) { - found = postProcessors[postProcessor](found, key, options); - } - } - - // process notFound if function exists - var splitNotFound = notFound; - if (notFound.indexOf(o.nsseparator) > -1) { - parts = notFound.split(o.nsseparator); - splitNotFound = parts[1]; - } - if (splitNotFound === key && o.parseMissingKey) { - notFound = o.parseMissingKey(notFound); - } - - if (found === undefined) { - notFound = applyReplacement(notFound, options); - notFound = applyReuse(notFound, options); - - if (postProcessor && postProcessors[postProcessor]) { - var val = _getDefaultValue(key, options); - found = postProcessors[postProcessor](val, key, options); - } - } - - return (found !== undefined) ? found : notFound; - } - - function _find(key, options) { - options = options || {}; - - var optionWithoutCount, translated - , notFound = _getDefaultValue(key, options) - , lngs = languages; - - if (!resStore) { return notFound; } // no resStore to translate from - - // CI mode - if (lngs[0].toLowerCase() === 'cimode') return notFound; - - // passed in lng - if (options.lng) { - lngs = f.toLanguages(options.lng); - - if (!resStore[lngs[0]]) { - var oldAsync = o.getAsync; - o.getAsync = false; - - TAPi18next.sync.load(lngs, o, function(err, store) { - f.extend(resStore, store); - o.getAsync = oldAsync; - }); - } - } - - var ns = options.ns || o.ns.defaultNs; - if (key.indexOf(o.nsseparator) > -1) { - var parts = key.split(o.nsseparator); - ns = parts[0]; - key = parts[1]; - } - - if (hasContext(options)) { - optionWithoutCount = f.extend({}, options); - delete optionWithoutCount.context; - optionWithoutCount.defaultValue = o.contextNotFound; - - var contextKey = ns + o.nsseparator + key + '_' + options.context; - - translated = translate(contextKey, optionWithoutCount); - if (translated != o.contextNotFound) { - return applyReplacement(translated, { context: options.context }); // apply replacement for context only - } // else continue translation with original/nonContext key - } - - if (needsPlural(options)) { - optionWithoutCount = f.extend({}, options); - delete optionWithoutCount.count; - optionWithoutCount.defaultValue = o.pluralNotFound; - - var pluralKey = ns + o.nsseparator + key + o.pluralSuffix; - var pluralExtension = pluralExtensions.get(lngs[0], options.count); - if (pluralExtension >= 0) { - pluralKey = pluralKey + '_' + pluralExtension; - } else if (pluralExtension === 1) { - pluralKey = ns + o.nsseparator + key; // singular - } - - translated = translate(pluralKey, optionWithoutCount); - if (translated != o.pluralNotFound) { - return applyReplacement(translated, { - count: options.count, - interpolationPrefix: options.interpolationPrefix, - interpolationSuffix: options.interpolationSuffix - }); // apply replacement for count only - } // else continue translation with original/singular key - } - - var found; - var keys = key.split(o.keyseparator); - for (var i = 0, len = lngs.length; i < len; i++ ) { - if (found !== undefined) break; - - var l = lngs[i]; - - var x = 0; - var value = resStore[l] && resStore[l][ns]; - while (keys[x]) { - value = value && value[keys[x]]; - x++; - } - if (value !== undefined) { - var valueType = Object.prototype.toString.apply(value); - if (typeof value === 'string') { - value = applyReplacement(value, options); - value = applyReuse(value, options); - } else if (valueType === '[object Array]' && !o.returnObjectTrees && !options.returnObjectTrees) { - value = value.join('\n'); - value = applyReplacement(value, options); - value = applyReuse(value, options); - } else if (value === null && o.fallbackOnNull === true) { - value = undefined; - } else if (value !== null) { - if (!o.returnObjectTrees && !options.returnObjectTrees) { - if (o.objectTreeKeyHandler && typeof o.objectTreeKeyHandler == 'function') { - value = o.objectTreeKeyHandler(key, value, l, ns, options); - } else { - value = 'key \'' + ns + ':' + key + ' (' + l + ')\' ' + - 'returned an object instead of string.'; - f.log(value); - } - } else if (valueType !== '[object Number]' && valueType !== '[object Function]' && valueType !== '[object RegExp]') { - var copy = (valueType === '[object Array]') ? [] : {}; // apply child translation on a copy - f.each(value, function(m) { - copy[m] = _translate(ns + o.nsseparator + key + o.keyseparator + m, options); - }); - value = copy; - } - } - - if (typeof value === 'string' && value.trim() === '' && o.fallbackOnEmpty === true) - value = undefined; - - found = value; - } - } - - if (found === undefined && !options.isFallbackLookup && (o.fallbackToDefaultNS === true || (o.fallbackNS && o.fallbackNS.length > 0))) { - // set flag for fallback lookup - avoid recursion - options.isFallbackLookup = true; - - if (o.fallbackNS.length) { - - for (var y = 0, lenY = o.fallbackNS.length; y < lenY; y++) { - found = _find(o.fallbackNS[y] + o.nsseparator + key, options); - - if (found) { - /* compare value without namespace */ - var foundValue = found.indexOf(o.nsseparator) > -1 ? found.split(o.nsseparator)[1] : found - , notFoundValue = notFound.indexOf(o.nsseparator) > -1 ? notFound.split(o.nsseparator)[1] : notFound; - - if (foundValue !== notFoundValue) break; - } - } - } else { - found = _find(key, options); // fallback to default NS - } - } - - return found; - } - function detectLanguage() { - var detectedLng; - - // get from qs - var qsParm = []; - if (typeof window !== 'undefined') { - (function() { - var query = window.location.search.substring(1); - var parms = query.split('&'); - for (var i=0; i 0) { - var key = parms[i].substring(0,pos); - var val = parms[i].substring(pos+1); - qsParm[key] = val; - } - } - })(); - if (qsParm[o.detectLngQS]) { - detectedLng = qsParm[o.detectLngQS]; - } - } - - // get from cookie - if (!detectedLng && typeof document !== 'undefined' && o.useCookie ) { - var c = f.cookie.read(o.cookieName); - if (c) detectedLng = c; - } - - // get from navigator - if (!detectedLng && typeof navigator !== 'undefined') { - detectedLng = (navigator.language) ? navigator.language : navigator.userLanguage; - } - - return detectedLng; - } - var sync = { - - load: function(lngs, options, cb) { - if (options.useLocalStorage) { - sync._loadLocal(lngs, options, function(err, store) { - var missingLngs = []; - for (var i = 0, len = lngs.length; i < len; i++) { - if (!store[lngs[i]]) missingLngs.push(lngs[i]); - } - - if (missingLngs.length > 0) { - sync._fetch(missingLngs, options, function(err, fetched) { - f.extend(store, fetched); - sync._storeLocal(fetched); - - cb(null, store); - }); - } else { - cb(null, store); - } - }); - } else { - sync._fetch(lngs, options, function(err, store){ - cb(null, store); - }); - } - }, - - _loadLocal: function(lngs, options, cb) { - var store = {} - , nowMS = new Date().getTime(); - - if(window.localStorage) { - - var todo = lngs.length; - - f.each(lngs, function(key, lng) { - var local = window.localStorage.getItem('res_' + lng); - - if (local) { - local = JSON.parse(local); - - if (local.i18nStamp && local.i18nStamp + options.localStorageExpirationTime > nowMS) { - store[lng] = local; - } - } - - todo--; // wait for all done befor callback - if (todo === 0) cb(null, store); - }); - } - }, - - _storeLocal: function(store) { - if(window.localStorage) { - for (var m in store) { - store[m].i18nStamp = new Date().getTime(); - window.localStorage.setItem('res_' + m, JSON.stringify(store[m])); - } - } - return; - }, - - _fetch: function(lngs, options, cb) { - var ns = options.ns - , store = {}; - - if (!options.dynamicLoad) { - var todo = ns.namespaces.length * lngs.length - , errors; - - // load each file individual - f.each(ns.namespaces, function(nsIndex, nsValue) { - f.each(lngs, function(lngIndex, lngValue) { - - // Call this once our translation has returned. - var loadComplete = function(err, data) { - if (err) { - errors = errors || []; - errors.push(err); - } - store[lngValue] = store[lngValue] || {}; - store[lngValue][nsValue] = data; - - todo--; // wait for all done befor callback - if (todo === 0) cb(errors, store); - }; - - if(typeof options.customLoad == 'function'){ - // Use the specified custom callback. - options.customLoad(lngValue, nsValue, options, loadComplete); - } else { - //~ // Use our inbuilt sync. - sync._fetchOne(lngValue, nsValue, options, loadComplete); - } - }); - }); - } else { - // Call this once our translation has returned. - var loadComplete = function(err, data) { - cb(null, data); - }; - - if(typeof options.customLoad == 'function'){ - // Use the specified custom callback. - options.customLoad(lngs, ns.namespaces, options, loadComplete); - } else { - var url = applyReplacement(options.resGetPath, { lng: lngs.join('+'), ns: ns.namespaces.join('+') }); - // load all needed stuff once - f.ajax({ - url: url, - success: function(data, status, xhr) { - f.log('loaded: ' + url); - loadComplete(null, data); - }, - error : function(xhr, status, error) { - f.log('failed loading: ' + url); - loadComplete('failed loading resource.json error: ' + error); - }, - dataType: "json", - async : options.getAsync - }); - } - } - }, - - _fetchOne: function(lng, ns, options, done) { - var url = applyReplacement(options.resGetPath, { lng: lng, ns: ns }); - f.ajax({ - url: url, - success: function(data, status, xhr) { - f.log('loaded: ' + url); - done(null, data); - }, - error : function(xhr, status, error) { - if ((status && status == 200) || (xhr && xhr.status && xhr.status == 200)) { - // file loaded but invalid json, stop waste time ! - f.log('There is a typo in: ' + url); - } else if ((status && status == 404) || (xhr && xhr.status && xhr.status == 404)) { - f.log('Does not exist: ' + url); - } else { - var theStatus = status ? status : ((xhr && xhr.status) ? xhr.status : null); - f.log(theStatus + ' when loading ' + url); - } - - done(error, {}); - }, - dataType: "json", - async : options.getAsync - }); - }, - - postMissing: function(lng, ns, key, defaultValue, lngs) { - var payload = {}; - payload[key] = defaultValue; - - var urls = []; - - if (o.sendMissingTo === 'fallback' && o.fallbackLng[0] !== false) { - for (var i = 0; i < o.fallbackLng.length; i++) { - urls.push({lng: o.fallbackLng[i], url: applyReplacement(o.resPostPath, { lng: o.fallbackLng[i], ns: ns })}); - } - } else if (o.sendMissingTo === 'current' || (o.sendMissingTo === 'fallback' && o.fallbackLng[0] === false) ) { - urls.push({lng: lng, url: applyReplacement(o.resPostPath, { lng: lng, ns: ns })}); - } else if (o.sendMissingTo === 'all') { - for (var i = 0, l = lngs.length; i < l; i++) { - urls.push({lng: lngs[i], url: applyReplacement(o.resPostPath, { lng: lngs[i], ns: ns })}); - } - } - - for (var y = 0, len = urls.length; y < len; y++) { - var item = urls[y]; - f.ajax({ - url: item.url, - type: o.sendType, - data: payload, - success: function(data, status, xhr) { - f.log('posted missing key \'' + key + '\' to: ' + item.url); - - // add key to resStore - var keys = key.split('.'); - var x = 0; - var value = resStore[item.lng][ns]; - while (keys[x]) { - if (x === keys.length - 1) { - value = value[keys[x]] = defaultValue; - } else { - value = value[keys[x]] = value[keys[x]] || {}; - } - x++; - } - }, - error : function(xhr, status, error) { - f.log('failed posting missing key \'' + key + '\' to: ' + item.url); - }, - dataType: "json", - async : o.postAsync - }); - } - } - }; - // definition http://translate.sourceforge.net/wiki/l10n/pluralforms - var pluralExtensions = { - - rules: { - "ach": { - "name": "Acholi", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "af": { - "name": "Afrikaans", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "ak": { - "name": "Akan", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "am": { - "name": "Amharic", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "an": { - "name": "Aragonese", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "ar": { - "name": "Arabic", - "numbers": [ - 0, - 1, - 2, - 3, - 11, - 100 - ], - "plurals": function(n) { return Number(n===0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5); } - }, - "arn": { - "name": "Mapudungun", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "ast": { - "name": "Asturian", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "ay": { - "name": "Aymar\u00e1", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "az": { - "name": "Azerbaijani", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "be": { - "name": "Belarusian", - "numbers": [ - 1, - 2, - 5 - ], - "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); } - }, - "bg": { - "name": "Bulgarian", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "bn": { - "name": "Bengali", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "bo": { - "name": "Tibetan", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "br": { - "name": "Breton", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "bs": { - "name": "Bosnian", - "numbers": [ - 1, - 2, - 5 - ], - "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); } - }, - "ca": { - "name": "Catalan", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "cgg": { - "name": "Chiga", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "cs": { - "name": "Czech", - "numbers": [ - 1, - 2, - 5 - ], - "plurals": function(n) { return Number((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2); } - }, - "csb": { - "name": "Kashubian", - "numbers": [ - 1, - 2, - 5 - ], - "plurals": function(n) { return Number(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); } - }, - "cy": { - "name": "Welsh", - "numbers": [ - 1, - 2, - 3, - 8 - ], - "plurals": function(n) { return Number((n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3); } - }, - "da": { - "name": "Danish", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "de": { - "name": "German", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "dz": { - "name": "Dzongkha", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "el": { - "name": "Greek", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "en": { - "name": "English", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "eo": { - "name": "Esperanto", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "es": { - "name": "Spanish", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "es_ar": { - "name": "Argentinean Spanish", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "et": { - "name": "Estonian", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "eu": { - "name": "Basque", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "fa": { - "name": "Persian", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "fi": { - "name": "Finnish", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "fil": { - "name": "Filipino", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "fo": { - "name": "Faroese", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "fr": { - "name": "French", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "fur": { - "name": "Friulian", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "fy": { - "name": "Frisian", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "ga": { - "name": "Irish", - "numbers": [ - 1, - 2, - 3, - 7, - 11 - ], - "plurals": function(n) { return Number(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4) ;} - }, - "gd": { - "name": "Scottish Gaelic", - "numbers": [ - 1, - 2, - 3, - 20 - ], - "plurals": function(n) { return Number((n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3); } - }, - "gl": { - "name": "Galician", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "gu": { - "name": "Gujarati", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "gun": { - "name": "Gun", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "ha": { - "name": "Hausa", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "he": { - "name": "Hebrew", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "hi": { - "name": "Hindi", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "hr": { - "name": "Croatian", - "numbers": [ - 1, - 2, - 5 - ], - "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); } - }, - "hu": { - "name": "Hungarian", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "hy": { - "name": "Armenian", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "ia": { - "name": "Interlingua", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "id": { - "name": "Indonesian", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "is": { - "name": "Icelandic", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n%10!=1 || n%100==11); } - }, - "it": { - "name": "Italian", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "ja": { - "name": "Japanese", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "jbo": { - "name": "Lojban", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "jv": { - "name": "Javanese", - "numbers": [ - 0, - 1 - ], - "plurals": function(n) { return Number(n !== 0); } - }, - "ka": { - "name": "Georgian", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "kk": { - "name": "Kazakh", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "km": { - "name": "Khmer", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "kn": { - "name": "Kannada", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "ko": { - "name": "Korean", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "ku": { - "name": "Kurdish", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "kw": { - "name": "Cornish", - "numbers": [ - 1, - 2, - 3, - 4 - ], - "plurals": function(n) { return Number((n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : 3); } - }, - "ky": { - "name": "Kyrgyz", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "lb": { - "name": "Letzeburgesch", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "ln": { - "name": "Lingala", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "lo": { - "name": "Lao", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "lt": { - "name": "Lithuanian", - "numbers": [ - 1, - 2, - 10 - ], - "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2); } - }, - "lv": { - "name": "Latvian", - "numbers": [ - 1, - 2, - 0 - ], - "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n !== 0 ? 1 : 2); } - }, - "mai": { - "name": "Maithili", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "mfe": { - "name": "Mauritian Creole", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "mg": { - "name": "Malagasy", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "mi": { - "name": "Maori", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "mk": { - "name": "Macedonian", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n==1 || n%10==1 ? 0 : 1); } - }, - "ml": { - "name": "Malayalam", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "mn": { - "name": "Mongolian", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "mnk": { - "name": "Mandinka", - "numbers": [ - 0, - 1, - 2 - ], - "plurals": function(n) { return Number(n == 0 ? 0 : n==1 ? 1 : 2); } - }, - "mr": { - "name": "Marathi", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "ms": { - "name": "Malay", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "mt": { - "name": "Maltese", - "numbers": [ - 1, - 2, - 11, - 20 - ], - "plurals": function(n) { return Number(n==1 ? 0 : n===0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3); } - }, - "nah": { - "name": "Nahuatl", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "nap": { - "name": "Neapolitan", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "nb": { - "name": "Norwegian Bokmal", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "ne": { - "name": "Nepali", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "nl": { - "name": "Dutch", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "nn": { - "name": "Norwegian Nynorsk", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "no": { - "name": "Norwegian", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "nso": { - "name": "Northern Sotho", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "oc": { - "name": "Occitan", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "or": { - "name": "Oriya", - "numbers": [ - 2, - 1 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "pa": { - "name": "Punjabi", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "pap": { - "name": "Papiamento", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "pl": { - "name": "Polish", - "numbers": [ - 1, - 2, - 5 - ], - "plurals": function(n) { return Number(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); } - }, - "pms": { - "name": "Piemontese", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "ps": { - "name": "Pashto", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "pt": { - "name": "Portuguese", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "pt_br": { - "name": "Brazilian Portuguese", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "rm": { - "name": "Romansh", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "ro": { - "name": "Romanian", - "numbers": [ - 1, - 2, - 20 - ], - "plurals": function(n) { return Number(n==1 ? 0 : (n===0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2); } - }, - "ru": { - "name": "Russian", - "numbers": [ - 1, - 2, - 5 - ], - "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); } - }, - "sah": { - "name": "Yakut", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "sco": { - "name": "Scots", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "se": { - "name": "Northern Sami", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "si": { - "name": "Sinhala", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "sk": { - "name": "Slovak", - "numbers": [ - 1, - 2, - 5 - ], - "plurals": function(n) { return Number((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2); } - }, - "sl": { - "name": "Slovenian", - "numbers": [ - 5, - 1, - 2, - 3 - ], - "plurals": function(n) { return Number(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0); } - }, - "so": { - "name": "Somali", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "son": { - "name": "Songhay", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "sq": { - "name": "Albanian", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "sr": { - "name": "Serbian", - "numbers": [ - 1, - 2, - 5 - ], - "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); } - }, - "su": { - "name": "Sundanese", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "sv": { - "name": "Swedish", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "sw": { - "name": "Swahili", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "ta": { - "name": "Tamil", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "te": { - "name": "Telugu", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "tg": { - "name": "Tajik", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "th": { - "name": "Thai", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "ti": { - "name": "Tigrinya", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "tk": { - "name": "Turkmen", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "tr": { - "name": "Turkish", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "tt": { - "name": "Tatar", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "ug": { - "name": "Uyghur", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "uk": { - "name": "Ukrainian", - "numbers": [ - 1, - 2, - 5 - ], - "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); } - }, - "ur": { - "name": "Urdu", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "uz": { - "name": "Uzbek", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "vi": { - "name": "Vietnamese", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "wa": { - "name": "Walloon", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n > 1); } - }, - "wo": { - "name": "Wolof", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - }, - "yo": { - "name": "Yoruba", - "numbers": [ - 1, - 2 - ], - "plurals": function(n) { return Number(n != 1); } - }, - "zh": { - "name": "Chinese", - "numbers": [ - 1 - ], - "plurals": function(n) { return 0; } - } - }, - - // for demonstration only sl and ar is added but you can add your own pluralExtensions - addRule: function(lng, obj) { - pluralExtensions.rules[lng] = obj; - }, - - setCurrentLng: function(lng) { - if (!pluralExtensions.currentRule || pluralExtensions.currentRule.lng !== lng) { - var parts = lng.split('-'); - - pluralExtensions.currentRule = { - lng: lng, - rule: pluralExtensions.rules[parts[0]] - }; - } - }, - - get: function(lng, count) { - var parts = lng.split('-'); - - function getResult(l, c) { - var ext; - if (pluralExtensions.currentRule && pluralExtensions.currentRule.lng === lng) { - ext = pluralExtensions.currentRule.rule; - } else { - ext = pluralExtensions.rules[l]; - } - if (ext) { - var i = ext.plurals(c); - var number = ext.numbers[i]; - if (ext.numbers.length === 2 && ext.numbers[0] === 1) { - if (number === 2) { - number = -1; // regular plural - } else if (number === 1) { - number = 1; // singular - } - }//console.log(count + '-' + number); - return number; - } else { - return c === 1 ? '1' : '-1'; - } - } - - return getResult(parts[0], count); - } - - }; - var postProcessors = {}; - var addPostProcessor = function(name, fc) { - postProcessors[name] = fc; - }; - // sprintf support - var sprintf = (function() { - function get_type(variable) { - return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase(); - } - function str_repeat(input, multiplier) { - for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */} - return output.join(''); - } - - var str_format = function() { - if (!str_format.cache.hasOwnProperty(arguments[0])) { - str_format.cache[arguments[0]] = str_format.parse(arguments[0]); - } - return str_format.format.call(null, str_format.cache[arguments[0]], arguments); - }; - - str_format.format = function(parse_tree, argv) { - var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length; - for (i = 0; i < tree_length; i++) { - node_type = get_type(parse_tree[i]); - if (node_type === 'string') { - output.push(parse_tree[i]); - } - else if (node_type === 'array') { - match = parse_tree[i]; // convenience purposes only - if (match[2]) { // keyword argument - arg = argv[cursor]; - for (k = 0; k < match[2].length; k++) { - if (!arg.hasOwnProperty(match[2][k])) { - throw(sprintf('[sprintf] property "%s" does not exist', match[2][k])); - } - arg = arg[match[2][k]]; - } - } - else if (match[1]) { // positional argument (explicit) - arg = argv[match[1]]; - } - else { // positional argument (implicit) - arg = argv[cursor++]; - } - - if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) { - throw(sprintf('[sprintf] expecting number but found %s', get_type(arg))); - } - switch (match[8]) { - case 'b': arg = arg.toString(2); break; - case 'c': arg = String.fromCharCode(arg); break; - case 'd': arg = parseInt(arg, 10); break; - case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break; - case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break; - case 'o': arg = arg.toString(8); break; - case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break; - case 'u': arg = Math.abs(arg); break; - case 'x': arg = arg.toString(16); break; - case 'X': arg = arg.toString(16).toUpperCase(); break; - } - arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg); - pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' '; - pad_length = match[6] - String(arg).length; - pad = match[6] ? str_repeat(pad_character, pad_length) : ''; - output.push(match[5] ? arg + pad : pad + arg); - } - } - return output.join(''); - }; - - str_format.cache = {}; - - str_format.parse = function(fmt) { - var _fmt = fmt, match = [], parse_tree = [], arg_names = 0; - while (_fmt) { - if ((match = /^[^\x25]+/.exec(_fmt)) !== null) { - parse_tree.push(match[0]); - } - else if ((match = /^\x25{2}/.exec(_fmt)) !== null) { - parse_tree.push('%'); - } - else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) { - if (match[2]) { - arg_names |= 1; - var field_list = [], replacement_field = match[2], field_match = []; - if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { - field_list.push(field_match[1]); - while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') { - if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { - field_list.push(field_match[1]); - } - else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) { - field_list.push(field_match[1]); - } - else { - throw('[sprintf] huh?'); - } - } - } - else { - throw('[sprintf] huh?'); - } - match[2] = field_list; - } - else { - arg_names |= 2; - } - if (arg_names === 3) { - throw('[sprintf] mixing positional and named placeholders is not (yet) supported'); - } - parse_tree.push(match); - } - else { - throw('[sprintf] huh?'); - } - _fmt = _fmt.substring(match[0].length); - } - return parse_tree; - }; - - return str_format; - })(); - - var vsprintf = function(fmt, argv) { - argv.unshift(fmt); - return sprintf.apply(null, argv); - }; - - addPostProcessor("sprintf", function(val, key, opts) { - if (!opts.sprintf) return val; - - if (Object.prototype.toString.apply(opts.sprintf) === '[object Array]') { - return vsprintf(val, opts.sprintf); - } else if (typeof opts.sprintf === 'object') { - return sprintf(val, opts.sprintf); - } - - return val; - }); - // public api interface - TAPi18next.init = init; - TAPi18next.setLng = setLng; - TAPi18next.preload = preload; - TAPi18next.addResourceBundle = addResourceBundle; - TAPi18next.removeResourceBundle = removeResourceBundle; - TAPi18next.loadNamespace = loadNamespace; - TAPi18next.loadNamespaces = loadNamespaces; - TAPi18next.setDefaultNamespace = setDefaultNamespace; - TAPi18next.t = translate; - TAPi18next.translate = translate; - TAPi18next.exists = exists; - TAPi18next.detectLanguage = f.detectLanguage; - TAPi18next.pluralExtensions = pluralExtensions; - TAPi18next.sync = sync; - TAPi18next.functions = f; - TAPi18next.lng = lng; - TAPi18next.addPostProcessor = addPostProcessor; - TAPi18next.options = o; -})(); diff --git a/packages/tap-i18n/lib/tap_i18next/tap_i18next_init.js b/packages/tap-i18n/lib/tap_i18next/tap_i18next_init.js deleted file mode 100755 index 2d9cc458246d..000000000000 --- a/packages/tap-i18n/lib/tap_i18next/tap_i18next_init.js +++ /dev/null @@ -1 +0,0 @@ -TAPi18next.init({ resStore: {}, fallbackLng: globals.fallback_language, useCookie: false }); diff --git a/packages/tap-i18n/package.js b/packages/tap-i18n/package.js deleted file mode 100755 index d37799f4d3da..000000000000 --- a/packages/tap-i18n/package.js +++ /dev/null @@ -1,79 +0,0 @@ -Package.describe({ - name: 'tap:i18n', - summary: 'A comprehensive internationalization solution for Meteor', - version: '1.8.2', - git: 'https://github.com/TAPevents/tap-i18n', -}); - -const both = ['server', 'client']; -const server = 'server'; -const client = 'client'; - -Package.onUse(function(api) { - api.versionsFrom('0.9.4'); - - api.use('coffeescript', both); - api.use('underscore', both); - api.use('meteor', both); - - api.use('raix:eventemitter@0.1.1', both); - api.use('meteorspark:util@0.2.0', both); - - api.use('tracker', both); - api.use('session', client); - api.use('jquery', client); - api.use('templating', client); - - api.use('cfs:http-methods@0.0.27', server); - - // load TAPi18n - api.add_files('lib/globals.js', both); - - // load and init TAPi18next - api.add_files('lib/tap_i18next/tap_i18next-1.7.3.js', both); - api.export('TAPi18next'); - api.add_files('lib/tap_i18next/tap_i18next_init.js', both); - - api.add_files('lib/tap_i18n/tap_i18n-helpers.coffee', both); - - // We use the bare option since we need TAPi18n in the package level and - // coffee adds vars to all (so without bare all vars are in the file level) - api.add_files('lib/tap_i18n/tap_i18n-common.coffee', server); - api.add_files('lib/tap_i18n/tap_i18n-common.coffee', client, { bare: true }); - - api.add_files('lib/tap_i18n/tap_i18n-server.coffee', server); - api.add_files('lib/tap_i18n/tap_i18n-client.coffee', client, { bare: true }); - - api.add_files('lib/tap_i18n/tap_i18n-init.coffee', server); - api.add_files('lib/tap_i18n/tap_i18n-init.coffee', client, { bare: true }); - - api.export('TAPi18n'); -}); - -Package.registerBuildPlugin({ - name: 'tap-i18n-compiler', - use: ['coffeescript', 'underscore', 'mdg:validation-error', 'aldeed:simple-schema@1.3.0', 'check@1.0.3', 'templating'], - npmDependencies: { - yamljs: '0.2.4', - }, - sources: [ - 'lib/globals.js', - - 'lib/plugin/etc/language_names.js', - - 'lib/plugin/compiler_configuration.coffee', - - 'lib/plugin/helpers/helpers.coffee', - 'lib/plugin/helpers/load_json.coffee', - 'lib/plugin/helpers/load_yml.coffee', - 'lib/plugin/helpers/compile_step_helpers.coffee', - - 'lib/plugin/compilers/share.coffee', - 'lib/plugin/compilers/i18n.coffee', - 'lib/plugin/compilers/project-tap.i18n.coffee', - 'lib/plugin/compilers/package-tap.i18n.coffee', - 'lib/plugin/compilers/i18n.generic_compiler.coffee', - 'lib/plugin/compilers/i18n.json.coffee', - 'lib/plugin/compilers/i18n.yml.coffee', - ], -});