From 49a1f4cb8e96b3669fd727c20dcd3c1cb0e62642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Rizio?= Date: Fri, 6 May 2016 23:46:09 +0200 Subject: [PATCH] First version --- .eslintignore | 5 + .eslintrc.json | 30 ++++ .gitignore | 3 + README.md | 79 +++++++++++ bower.json | 27 ++++ demo/base/base.html | 173 ++++++++++++++++++++++++ demo/base/locales/en-US/test.json | 5 + demo/base/locales/en/context.json | 7 + demo/base/locales/en/default.json | 3 + demo/base/locales/en/global.json | 3 + demo/base/locales/en/interpolation.json | 6 + demo/base/locales/en/nesting.json | 11 ++ demo/base/locales/en/plural.json | 6 + demo/base/locales/en/test.json | 5 + demo/base/locales/fr/default.json | 3 + demo/base/locales/fr/global.json | 3 + demo/base/locales/fr/interpolation.json | 5 + demo/base/locales/fr/nesting.json | 3 + demo/base/locales/fr/test.json | 4 + demo/base/test.json | 8 ++ docs/index.html | 94 +++++++++++++ gulpfile.js | 164 ++++++++++++++++++++++ package.json | 18 +++ src/kwc-i18next.html | 6 + src/kwc-i18next.js | 91 +++++++++++++ 25 files changed, 762 insertions(+) create mode 100644 .eslintignore create mode 100644 .eslintrc.json create mode 100644 .gitignore create mode 100644 README.md create mode 100644 bower.json create mode 100644 demo/base/base.html create mode 100644 demo/base/locales/en-US/test.json create mode 100644 demo/base/locales/en/context.json create mode 100644 demo/base/locales/en/default.json create mode 100644 demo/base/locales/en/global.json create mode 100644 demo/base/locales/en/interpolation.json create mode 100644 demo/base/locales/en/nesting.json create mode 100644 demo/base/locales/en/plural.json create mode 100644 demo/base/locales/en/test.json create mode 100644 demo/base/locales/fr/default.json create mode 100644 demo/base/locales/fr/global.json create mode 100644 demo/base/locales/fr/interpolation.json create mode 100644 demo/base/locales/fr/nesting.json create mode 100644 demo/base/locales/fr/test.json create mode 100644 demo/base/test.json create mode 100644 docs/index.html create mode 100644 gulpfile.js create mode 100644 package.json create mode 100644 src/kwc-i18next.html create mode 100644 src/kwc-i18next.js diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..38d6d6e --- /dev/null +++ b/.eslintignore @@ -0,0 +1,5 @@ +/*.js +/*.html +bower_components +node_modules +/build \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..f9103f0 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,30 @@ +{ + "env": { + "browser": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 6 + }, + "rules": { + "indent": [ + "error", + 2 + ], + "linebreak-style": [ + "error", + "windows" + ], + "quotes": [ + "error", + "double" + ], + "semi": [ + "error", + "always" + ] + }, + "globals": { + "Polymer": true + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..372fe50 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/bower_components/ +/node_modules/ +/build \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..76cc16d --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ +This is a web component to exploit i18next. + +# <kwc-i18next> + +> A web component used to manage internationalization – replaces kwc-i18n + +## Install + +Install the component using [Bower](http://bower.io/): + +```sh +$ bower install kwc-i18next --save +``` + +Or [download as ZIP](https://github.com/successk/kwc-i18next/archive/master.zip). + +## Usage + +### 1 – Import polyfill: + +```html + +``` + +### 2 – Import custom element: + +```html + +``` + +### 3 – Start using it! + +```html + +``` + + +## Documentation + +See [docs](./docs) for options, children selector, methods, events and styles. + +## Development + +In order to run it locally you'll need to fetch some dependencies and a basic server setup. + +### 1 – Install [bower](http://bower.io/) & [gulp](http://gulpjs.com/): + +```sh +$ npm install -g bower gulp +$ npm install gulp +``` + +### 2 – Install local dependencies: + +```sh +$ bower install +$ npm install +``` + +### 3 – Start development server and open `http://localhost:8000/components/kwc-i18next/`. + +```sh +$ gulp dev +``` + +### 4 - build and minify file + +```sh +$ gulp build +$ gulp verify # test minified file +``` + +## History + +For detailed changelog, check [Releases](https://github.com/successk/kwc-i18next/releases). + +## License + +MIT \ No newline at end of file diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..a7f300c --- /dev/null +++ b/bower.json @@ -0,0 +1,27 @@ +{ + "name": "kwc-i18next", + "version": "0.1.0", + "description": "A web component used to manage internationalization – replaces kwc-i18n", + "license": "MIT", + "main": "kwc-i18next.html", + "keywords": [ + "polymer", + "web-component", + "i18n", + "i18next" + ], + "ignore": [ + "**/.*", + "bower_components", + "node_modules", + "test", + "tests" + ], + "dependencies": { + "polymer": "Polymer/polymer#^1.0.0" + }, + "homepage": "https://github.com/successk/kwc-i18next", + "authors": [ + "Gaëtan Rizio " + ] +} diff --git a/demo/base/base.html b/demo/base/base.html new file mode 100644 index 0000000..a1bc97d --- /dev/null +++ b/demo/base/base.html @@ -0,0 +1,173 @@ + + + + + <kwc-i18next> + + + + + + +
+

Base

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+
+ +
+

Interpolation

+

+ + +

+

+ + + + +

+

+ +

+

+ +

+

+ +

+
+ +
+

Nesting

+

+ +

+

+ +

+

+ +

+
+ +
+

Plural

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+
+ +
+

Context

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+
+ +
+ + + +
+ + + + + + \ No newline at end of file diff --git a/demo/base/locales/en-US/test.json b/demo/base/locales/en-US/test.json new file mode 100644 index 0000000..aaf789e --- /dev/null +++ b/demo/base/locales/en-US/test.json @@ -0,0 +1,5 @@ +{ + "title": "My US title", + "body": "My US body", + "footer": "My US footer" +} \ No newline at end of file diff --git a/demo/base/locales/en/context.json b/demo/base/locales/en/context.json new file mode 100644 index 0000000..582b323 --- /dev/null +++ b/demo/base/locales/en/context.json @@ -0,0 +1,7 @@ +{ + "friend": "A friend", + "friend_male": "A boyfriend", + "friend_female": "A girlfriend", + "friend_male_plural": "{{count}} boyfriends", + "friend_female_plural": "{{count}} girlfriends" +} \ No newline at end of file diff --git a/demo/base/locales/en/default.json b/demo/base/locales/en/default.json new file mode 100644 index 0000000..65ff0a1 --- /dev/null +++ b/demo/base/locales/en/default.json @@ -0,0 +1,3 @@ +{ + "key": "A key" +} \ No newline at end of file diff --git a/demo/base/locales/en/global.json b/demo/base/locales/en/global.json new file mode 100644 index 0000000..7e540ab --- /dev/null +++ b/demo/base/locales/en/global.json @@ -0,0 +1,3 @@ +{ + "undefined": "Please give a value" +} \ No newline at end of file diff --git a/demo/base/locales/en/interpolation.json b/demo/base/locales/en/interpolation.json new file mode 100644 index 0000000..7066ff2 --- /dev/null +++ b/demo/base/locales/en/interpolation.json @@ -0,0 +1,6 @@ +{ + "base": "A random value: {{text}}", + "html": "A value in HTML: {{-code}}", + "dangerous": "Maybe this code is dangerous: {{code}}", + "deep": "A complex variable: {{var.deep.deep}}" +} \ No newline at end of file diff --git a/demo/base/locales/en/nesting.json b/demo/base/locales/en/nesting.json new file mode 100644 index 0000000..9b8d955 --- /dev/null +++ b/demo/base/locales/en/nesting.json @@ -0,0 +1,11 @@ +{ + "nesting1": "en $t(nesting2)", + "nesting2": "2 $t(nesting3)", + "nesting3": "3", + "girlsAndBoys": "$t(nesting:girls, {\"count\": {{girls}} }) and {{count}} boy", + "girlsAndBoys_plural": "$t(nesting:girls, {\"count\": {{girls}} }) and {{count}} boys", + "girls": "{{count}} girl", + "girls_plural": "{{count}} girls", + "key1": "hello world", + "key2": "say: {{val}}" +} \ No newline at end of file diff --git a/demo/base/locales/en/plural.json b/demo/base/locales/en/plural.json new file mode 100644 index 0000000..cef6cc6 --- /dev/null +++ b/demo/base/locales/en/plural.json @@ -0,0 +1,6 @@ +{ + "key": "item", + "key_plural": "items", + "keyWithCount": "{{count}} item", + "keyWithCount_plural": "{{count}} items" +} \ No newline at end of file diff --git a/demo/base/locales/en/test.json b/demo/base/locales/en/test.json new file mode 100644 index 0000000..4c50e0b --- /dev/null +++ b/demo/base/locales/en/test.json @@ -0,0 +1,5 @@ +{ + "title": "My title", + "body": "My body", + "footer": "My footer" +} \ No newline at end of file diff --git a/demo/base/locales/fr/default.json b/demo/base/locales/fr/default.json new file mode 100644 index 0000000..7412c64 --- /dev/null +++ b/demo/base/locales/fr/default.json @@ -0,0 +1,3 @@ +{ + "key": "Une clef" +} \ No newline at end of file diff --git a/demo/base/locales/fr/global.json b/demo/base/locales/fr/global.json new file mode 100644 index 0000000..09f3221 --- /dev/null +++ b/demo/base/locales/fr/global.json @@ -0,0 +1,3 @@ +{ + "undefined": "Veuillez fournir une valeur" +} \ No newline at end of file diff --git a/demo/base/locales/fr/interpolation.json b/demo/base/locales/fr/interpolation.json new file mode 100644 index 0000000..f955816 --- /dev/null +++ b/demo/base/locales/fr/interpolation.json @@ -0,0 +1,5 @@ +{ + "first": "Une valeur aléatoire: {{text}}", + "second": "Une valeur en HTML: {{-code}}", + "dangerous": "Peut-être que ce code est dangereux: {{code}}" +} \ No newline at end of file diff --git a/demo/base/locales/fr/nesting.json b/demo/base/locales/fr/nesting.json new file mode 100644 index 0000000..8a95b91 --- /dev/null +++ b/demo/base/locales/fr/nesting.json @@ -0,0 +1,3 @@ +{ + "nesting1": "1 $t(nesting2)" +} \ No newline at end of file diff --git a/demo/base/locales/fr/test.json b/demo/base/locales/fr/test.json new file mode 100644 index 0000000..ead6152 --- /dev/null +++ b/demo/base/locales/fr/test.json @@ -0,0 +1,4 @@ +{ + "title": "Mon titre", + "body": "Mon corps" +} \ No newline at end of file diff --git a/demo/base/test.json b/demo/base/test.json new file mode 100644 index 0000000..780eaec --- /dev/null +++ b/demo/base/test.json @@ -0,0 +1,8 @@ +{ + "fr": { + "test": { + "title": "Mon titre", + "body": "Mon corps" + } + } +} \ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..db2081b --- /dev/null +++ b/docs/index.html @@ -0,0 +1,94 @@ + + + + + <kwc-i18next> + + + +

<kwc-i18next>

+ +
+ + +

Description

+ +

+ This component is based on i18next. + This component is just an interface to use this library as a component system. + Please go to its own documentation to understand how it works. +

+ +

Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeTypeDefaultPropertiesRequiredDescription
keyStringnull-The key of the translation
showBooleanfalse-×If true, shows the translation. If false, you should get the result from + var attribute +
varStringfalsereadOnly + reflectToAttribute + notify×If defined, the resulting translation will be set into this var.
not-escapeBooleanfalse-×If true, parameters will not be escaped. See i18next for more information
+ +

Children selectors

+ +

This component does not use children.

+ +

Methods

+ +

This component has no particular method.

+ +

Events

+ +

This component has no particular event (except notified attributes).

+ +

Custom styles

+ +

This component has particular style.

+ +

Examples

+ +

See demo for examples of uses.

+
+ + \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..8fff908 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,164 @@ +// Imports +const bowerConfig = require("./bower.json"); +const gulp = require("gulp"); +const gutil = require("gulp-util"); +const watch = require("gulp-watch"); +const babel = require("gulp-babel"); +const webserver = require("gulp-webserver"); +var uglify = require("gulp-uglify"); +var minifyInline = require("gulp-minify-inline"); +var htmlmin = require("gulp-htmlmin"); +var inlinesource = require("gulp-inline-source"); + +/// Constants +const tasks = Object.freeze({ + devHTML: "compileHTML", + devSrcHTML: "devSrcHTML", + devDemoHTML: "devDemoHTML", + devJS: "compileJS", + devSrcJS: "devSrcJS", + devDemoJS: "devDemoJS", + devDemoJSON: "devDemoJSON", + devDependencies: "devDependencies", + dev: "dev", + + buildHTML: "buildHTML", + buildJS: "buildJS", + inline: "inline", + build: "build", + + // used to check validity of built version + verifyBuild: "verifyBuild", + verifyDependencies: "verifyDependencies", + verifyDemoHTML: "verifyDemoHTML", + verifyDemoJS: "verifyDemoJS", + verify: "verify" +}); + +const paths = Object.freeze({ + srcHTML: "src/*.html", + srcJS: "src/*.js", + demoHTML: "demo/**/*.html", + demoJS: "demo/**/*.js", + demoJSON: "demo/**/*.json", + + dev: "build/dev", + devComponent: "build/dev/" + bowerConfig.name, + devDemo: "build/dev/demo", + + build: "build/compile", + builtHTML: "build/compile/*.html", + + verifyDemo: "build/verify/demo", + verify: "build/verify" +}); + +/// Helpers +function handleError(e) { + gutil.log(gutil.colors.red(e)); + this.emit("end"); +} + +function compileJS(source, dest) { + "use strict"; + return gulp.src(source) + .pipe(babel({ + presets: ["es2015"] + })) + .on("error", handleError) + .pipe(gulp.dest(dest)); +} + +function compileHTML(source, dest) { + "use strict"; + return gulp.src(source) + .on("error", handleError) + .pipe(gulp.dest(dest)); +} + +function dependencies(dest) { + "use strict"; + return gulp.src("bower_components/**/*") + .on("error", handleError) + .pipe(gulp.dest(dest)); +} + +/// Dev tasks +gulp.task(tasks.devSrcJS, () => compileJS(paths.srcJS, paths.devComponent)); + +gulp.task(tasks.devDemoJS, () => compileJS(paths.demoJS, paths.devDemo)); + +gulp.task(tasks.devDemoJSON, () => gulp.src(paths.demoJSON).pipe(gulp.dest(paths.devDemo))); + +gulp.task(tasks.devSrcHTML, () => compileHTML(paths.srcHTML, paths.devComponent)); + +gulp.task(tasks.devDemoHTML, () => compileHTML(paths.demoHTML, paths.devDemo)); + +gulp.task(tasks.devDependencies, () => dependencies(paths.dev)); + +gulp.task(tasks.dev, [tasks.devSrcJS, tasks.devDemoJS, tasks.devDemoJSON, tasks.devSrcHTML, tasks.devDemoHTML, tasks.devDependencies], function () { + gulp.watch(paths.demoJS, [tasks.devDemoJS]); + gulp.watch(paths.demoJSON, [tasks.devDemoJSON]); + gulp.watch(paths.srcJS, [tasks.devSrcJS]); + gulp.watch(paths.demoHTML, [tasks.devDemoHTML]); + gulp.watch(paths.srcHTML, [tasks.devSrcHTML]); + + gulp.src(paths.dev) + .pipe(webserver({ + host: "localhost", + port: 8000, + livereload: true, + directoryListing: true, + open: "http://localhost:8000/demo" + })); +}); + +/// Build tasks +gulp.task(tasks.buildHTML, () => + gulp.src(paths.srcHTML) + .pipe(minifyInline()) + .pipe(htmlmin({collapseWhitespace: true})) + .pipe(gulp.dest(paths.build)) +); + +gulp.task(tasks.buildJS, () => + gulp.src(paths.srcJS) + .pipe(babel({ + presets: ["es2015"] + })) + .pipe(uglify()) + .pipe(gulp.dest(paths.build)) +); + +gulp.task(tasks.inline, [tasks.buildHTML, tasks.buildJS], () => + gulp.src(paths.builtHTML) + .pipe(inlinesource()) + .pipe(gulp.dest(paths.build)) +); + +gulp.task(tasks.build, [tasks.inline], () => + gulp.src(paths.builtHTML) + .pipe(gulp.dest(".")) +); + +gulp.task(tasks.verifyBuild, [tasks.build], () => + gulp.src("./*.html") + .pipe(gulp.dest("bower_components/" + bowerConfig.name)) +); + +gulp.task(tasks.verifyDependencies, () => dependencies(paths.verify)); + +gulp.task(tasks.verifyDemoJS, () => compileJS(paths.demoJS, paths.verifyDemo)); + +gulp.task(tasks.verifyDemoHTML, () => compileHTML(paths.demoHTML, paths.verifyDemo)); + +gulp.task(tasks.verify, [tasks.verifyBuild, tasks.verifyDependencies, tasks.verifyDemoJS, tasks.verifyDemoHTML], () => + gulp.src(paths.verify) + .pipe(webserver({ + host: "localhost", + port: 8000, + livereload: false, + directoryListing: true, + open: "http://localhost:8000/demo" + })) +); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..21f0a1b --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "devDependencies": { + "babel": "~6.5.2", + "babel-plugin-transform-runtime": "^6.5.2", + "babel-preset-es2015": "^6.5.0", + "gulp": "^3.9.1", + "gulp-babel": "^6.1.2", + "gulp-htmlmin": "^1.3.0", + "gulp-inline-source": "^2.1.0", + "gulp-minify-inline": "^0.2.0", + "gulp-plumber": "^1.1.0", + "gulp-serve": "^1.2.0", + "gulp-uglify": "^1.5.3", + "gulp-util": "^3.0.7", + "gulp-watch": "^4.3.5", + "gulp-webserver": "^0.9.1" + } +} diff --git a/src/kwc-i18next.html b/src/kwc-i18next.html new file mode 100644 index 0000000..7eeaa73 --- /dev/null +++ b/src/kwc-i18next.html @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/kwc-i18next.js b/src/kwc-i18next.js new file mode 100644 index 0000000..a9cbae6 --- /dev/null +++ b/src/kwc-i18next.js @@ -0,0 +1,91 @@ +(() => { + "use strict"; + + class KwcI18next { + beforeRegister() { + this.is = "kwc-i18next"; + + this.properties = { + key: { + type: String, + value: null, + observer: "_update" + }, + show: { + type: Boolean, + value: false + }, + var: { + type: String, + value: null, + readOnly: true, + reflectToAttribute: true, + notify: true, + observer: "_updateDom" + }, + notEscape: { + type: Boolean, + value: false, + observer: "_update" + } + }; + } + + attached() { + const that = this; + this._isAttached = true; + this._update(); + window.i18next.on("initialized", () => that._update()); + window.i18next.on("loaded", () => that._update()); + window.i18next.on("languageChanged", () => that._update()); + + new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + if (mutation.type === "attributes") { + that._update(); + } + }); + }).observe(this, {attributes: true}); + } + + _update() { + if (this._isAttached) { + const options = this._getOptions(); + console.log(`i18next.t(${this.key}, ${JSON.stringify(options)})`); + this._setVar(window.i18next.t(this.key, options)); + } + } + + _getOptions() { + const options = this._getParameters(); + if (this.notEscape) { + options.interpolation = {escape: false}; + } + return options; + } + + _getParameters() { + const parameters = {}; + Array.from(this.attributes) + .filter((attr) => attr.name.startsWith("p-")) + .forEach((attr) => { + let value; + try { + value = JSON.parse(attr.value); + } catch (e) { + value = attr.value; + } + parameters[attr.name.substr(2)] = value; + }); + return parameters; + } + + _updateDom(value) { + if (this.show) { + this.innerHTML = value; + } + } + } + + Polymer(KwcI18next); +})(); \ No newline at end of file