mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Add low level i18n plugin
Manages languages that are available and is responsible for loading translated content at the granularity of a plugin. To be done: - APIs for store and retrieval
This commit is contained in:
parent
4b2ac10381
commit
aca671f10b
13 changed files with 348 additions and 0 deletions
2
src/plugins/i18n/.eslintrc
Normal file
2
src/plugins/i18n/.eslintrc
Normal file
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
extends: "@elastic/kibana"
|
2
src/plugins/i18n/.gitignore
vendored
Normal file
2
src/plugins/i18n/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
npm-debug.log*
|
||||
node_modules
|
25
src/plugins/i18n/README.md
Normal file
25
src/plugins/i18n/README.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
# i18n
|
||||
|
||||
> Core plugin which manages Kibana globalization
|
||||
|
||||
---
|
||||
|
||||
## development
|
||||
|
||||
See the [kibana contributing guide](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md) for instructions setting up your development environment. Once you have completed that, use the following npm tasks.
|
||||
|
||||
<dl>
|
||||
<dt><code>npm start</code></dt>
|
||||
<dd>Start kibana and have it include this plugin</dd>
|
||||
|
||||
<dt><code>npm run build</code></dt>
|
||||
<dd>Build a distributable archive</dd>
|
||||
|
||||
<dt><code>npm run test:browser</code></dt>
|
||||
<dd>Run the browser tests in a real web browser</dd>
|
||||
|
||||
<dt><code>npm run test:server</code></dt>
|
||||
<dd>Run the server tests using mocha</dd>
|
||||
</dl>
|
||||
|
||||
For more information about any of these commands run `npm run ${task} -- --help`.
|
10
src/plugins/i18n/index.js
Normal file
10
src/plugins/i18n/index.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import route from './server/route';
|
||||
|
||||
export default function (kibana) {
|
||||
return new kibana.Plugin({
|
||||
init(server, options) {
|
||||
// Add server routes and initalize the plugin here
|
||||
route(server);
|
||||
}
|
||||
});
|
||||
};
|
23
src/plugins/i18n/package.json
Normal file
23
src/plugins/i18n/package.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "i18n",
|
||||
"version": "0.0.0",
|
||||
"description": "Core plugin which manages Kibana globalization",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"lint": "eslint",
|
||||
"start": "plugin-helpers start",
|
||||
"test:server": "plugin-helpers test_server",
|
||||
"test:browser": "plugin-helpers test_browser",
|
||||
"build": "plugin-helpers build",
|
||||
"postinstall": "plugin-helpers postinstall"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@elastic/eslint-config-kibana": "0.0.2",
|
||||
"@elastic/plugin-helpers": "5.0.0-beta1",
|
||||
"babel-eslint": "4.1.8",
|
||||
"bluebird": "^3.4.0",
|
||||
"boom": "^3.2.1",
|
||||
"eslint": "1.10.3",
|
||||
"eslint-plugin-mocha": "1.1.0"
|
||||
}
|
||||
}
|
123
src/plugins/i18n/server/i18n.js
Normal file
123
src/plugins/i18n/server/i18n.js
Normal file
|
@ -0,0 +1,123 @@
|
|||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var process = require('child_process');
|
||||
var os = require('os');
|
||||
|
||||
const TRANSLATION_FILE_EXTENSION = 'json';
|
||||
|
||||
module.exports = {
|
||||
storePluginLanguageTranslations: function (pluginName, pluginTranslationPath, language) {
|
||||
var translationFiles = [];
|
||||
var languageList = [];
|
||||
var translationStorePath = __dirname + '/data/store_translations';
|
||||
var translationStorePluginPath = translationStorePath + '/' + pluginName;
|
||||
var translationFileName = language + '.' + TRANSLATION_FILE_EXTENSION;
|
||||
|
||||
module.exports.getPluginTranslationDetails(pluginTranslationPath, translationFiles, languageList);
|
||||
|
||||
var langSupported = false;
|
||||
for (var langIndx in languageList) {
|
||||
if (language === languageList[langIndx]) {
|
||||
langSupported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!langSupported) {
|
||||
return false;
|
||||
}
|
||||
if (!fs.existsSync(translationStorePluginPath)) {
|
||||
createDirectoriesRecursively(translationStorePluginPath);
|
||||
}
|
||||
|
||||
for (var fileIndx in translationFiles) {
|
||||
if (!translationFiles.hasOwnProperty(fileIndx)) continue;
|
||||
var translationFile = translationFiles[fileIndx];
|
||||
var pluginTranslationFileName = getFileName(translationFile);
|
||||
if (pluginTranslationFileName !== translationFileName) continue;
|
||||
var translationJson = require(translationFile);
|
||||
var fileToWrite = translationStorePluginPath + '/' + translationFileName;
|
||||
saveTranslationToFile(fileToWrite, translationJson);
|
||||
}
|
||||
|
||||
return translationFiles;
|
||||
},
|
||||
|
||||
getPluginLanguageTranslation: function (pluginName, language) {
|
||||
var translationStorePath = __dirname + '/data/store_translations';
|
||||
var translationStorePluginPath = translationStorePath + '/' + pluginName;
|
||||
var translationFileName = language + '.' + TRANSLATION_FILE_EXTENSION;
|
||||
var translationFile = translationStorePluginPath + '/' + translationFileName;
|
||||
|
||||
var translationStr = fs.readFileSync(translationFile);
|
||||
return JSON.parse(translationStr);
|
||||
},
|
||||
|
||||
getPluginTranslationDetails: function (pluginTranslationPath, translationFiles, languageList) {
|
||||
|
||||
getFilesRecursivelyFromTopDir(pluginTranslationPath, function parseDetails(fullPath) {
|
||||
var files = getFilesFromDir(fullPath);
|
||||
var fileLength = files.length;
|
||||
for (var i = 0; i < fileLength; i++) {
|
||||
var fullFilePath = files[i];
|
||||
var fileName = getFileName(fullFilePath);
|
||||
var fileExt = fileName.split('.').pop();
|
||||
if (fileName === fileExt) continue;
|
||||
if (fileExt !== TRANSLATION_FILE_EXTENSION) continue;
|
||||
translationFiles.push(fullFilePath);
|
||||
var lang = fileName.substr(0, fileName.lastIndexOf('.'));
|
||||
if (languageList.indexOf(lang) !== -1) {
|
||||
continue;
|
||||
}
|
||||
languageList.push(lang);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
function saveTranslationToFile(translationFullFileName, translationJson) {
|
||||
var jsonToWrite = [];
|
||||
if (fs.existsSync(translationFullFileName)) {
|
||||
var prevTranslationJson = require(translationFullFileName);
|
||||
jsonToWrite = prevTranslationJson.concat(translationJson);
|
||||
} else {
|
||||
jsonToWrite = translationJson;
|
||||
}
|
||||
fs.writeFileSync(translationFullFileName, JSON.stringify(jsonToWrite, null, 4));
|
||||
}
|
||||
|
||||
function getFilesRecursivelyFromTopDir(topDir, fileCallback) {
|
||||
fs.readdirSync(topDir).forEach(function (name) {
|
||||
var fullPath = path.join(topDir, name);
|
||||
var stat = fs.statSync(fullPath);
|
||||
if (stat.isDirectory()) {
|
||||
fileCallback(fullPath);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getFilesFromDir(dir) {
|
||||
var fileList = [];
|
||||
|
||||
var files = fs.readdirSync(dir);
|
||||
for (var i in files) {
|
||||
if (!files.hasOwnProperty(i)) continue;
|
||||
var name = dir + '/' + files[i];
|
||||
if (!fs.statSync(name).isDirectory()) {
|
||||
fileList.push(name);
|
||||
}
|
||||
}
|
||||
return fileList;
|
||||
}
|
||||
|
||||
function getFileName(fullPath) {
|
||||
return fullPath.replace(/^.*[\\\/]/, '');
|
||||
}
|
||||
|
||||
// Added this function because 'mkdirp' does not add more than 2 subdirectories
|
||||
function createDirectoriesRecursively(fullDir) {
|
||||
process.exec('mkdir -p ' + fullDir, function (err,stdout,stderr) {
|
||||
if (err) throw err;
|
||||
});
|
||||
}
|
||||
|
12
src/plugins/i18n/server/route.js
Normal file
12
src/plugins/i18n/server/route.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
export default function (server) {
|
||||
|
||||
server.route({
|
||||
path: '/api/i18n/default',
|
||||
method: 'GET',
|
||||
handler(req, reply) {
|
||||
reply('Hello World!');
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
[
|
||||
{
|
||||
"NO_SSL": "Dont run the DE dev server using HTTPS",
|
||||
"DEV": "Run the DE server with development mode defaults"
|
||||
}
|
||||
]
|
|
@ -0,0 +1,9 @@
|
|||
[{
|
||||
"NO_SSL": "Dont run the dev server using HTTPS",
|
||||
"DEV": "Run the server with development mode defaults"
|
||||
},
|
||||
{
|
||||
"NO_RUN_SERVER": "Dont run the dev server",
|
||||
"HOME": "Run along home now!"
|
||||
}
|
||||
]
|
118
src/plugins/i18n/server/tests/i18n_tests.js
Normal file
118
src/plugins/i18n/server/tests/i18n_tests.js
Normal file
|
@ -0,0 +1,118 @@
|
|||
import expect from 'expect.js';
|
||||
|
||||
var process = require('child_process');
|
||||
var i18n = require('../i18n');
|
||||
|
||||
describe('Test plugin translations details for test_plugin_1', function () {
|
||||
var pluginName = 'test_plugin_1';
|
||||
var pluginTranslationPath = __dirname + '/' + pluginName + '/translations';
|
||||
|
||||
it('2 translation languages exist', function () {
|
||||
var result = true;
|
||||
var expectedLanguages = ['en', 'de'];
|
||||
var actualLanguages = getPluginTranslationLanguages(pluginName, pluginTranslationPath);
|
||||
if (actualLanguages.length !== expectedLanguages.length) {
|
||||
result = false;
|
||||
} else {
|
||||
var index = actualLanguages.length;
|
||||
actualLanguages.sort();
|
||||
expectedLanguages.sort();
|
||||
while (index--) {
|
||||
if (actualLanguages[index] !== expectedLanguages[index]) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
expect(result).to.be(true);
|
||||
});
|
||||
|
||||
it('2 translation languages exist and wrongly expecting 1', function () {
|
||||
var result = true;
|
||||
var expectedLanguages = ['de'];
|
||||
var actualLanguages = getPluginTranslationLanguages(pluginName, pluginTranslationPath);
|
||||
if (actualLanguages.length !== expectedLanguages.length) {
|
||||
result = false;
|
||||
} else {
|
||||
var index = actualLanguages.length;
|
||||
actualLanguages.sort();
|
||||
expectedLanguages.sort();
|
||||
while (index--) {
|
||||
if (actualLanguages[index] !== expectedLanguages[index]) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
expect(result).to.be(false);
|
||||
});
|
||||
it('Translation files exist', function () {
|
||||
var result = true;
|
||||
var expectedFiles = [
|
||||
pluginTranslationPath + '/view1/de.json',
|
||||
pluginTranslationPath + '/view1/en.json',
|
||||
pluginTranslationPath + '/view2/en.json'
|
||||
];
|
||||
var actualFiles = getPluginTranslationFiles(pluginName, pluginTranslationPath);
|
||||
if (actualFiles.length !== expectedFiles.length) {
|
||||
result = false;
|
||||
} else {
|
||||
var index = actualFiles.length;
|
||||
actualFiles.sort();
|
||||
expectedFiles.sort();
|
||||
while (index--) {
|
||||
if (actualFiles[index] !== expectedFiles[index]) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
expect(result).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test storing translations for test_plugin_1', function () {
|
||||
var pluginName = 'test_plugin_1';
|
||||
var pluginTranslationPath = __dirname + '/' + pluginName + '/translations';
|
||||
|
||||
it('Translation plugin bundle for English' , function () {
|
||||
var result = true;
|
||||
var language = 'en';
|
||||
|
||||
if (!i18n.storePluginLanguageTranslations(pluginName, pluginTranslationPath, language)) {
|
||||
result = false;
|
||||
} else {
|
||||
var expectedTranslationJsonFile = __dirname + '/data/reference/' + pluginName + '/' + language + '.json';
|
||||
var expectedTranslationJson = require(expectedTranslationJsonFile);
|
||||
expectedTranslationJson = JSON.stringify(expectedTranslationJson);
|
||||
var actualTranslationJson = i18n.getPluginLanguageTranslation(pluginName, language);
|
||||
actualTranslationJson = JSON.stringify(actualTranslationJson);
|
||||
if (actualTranslationJson !== expectedTranslationJson) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
expect(result).to.be(true);
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
var translationStorePath = __dirname + '/../data/store_translations';
|
||||
process.exec('rm -rf ' + translationStorePath + '/test_plugin_1', function (err,stdout,stderr) {
|
||||
if (err) throw err;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function getPluginTranslationLanguages(pluginName, pluginTranslationPath) {
|
||||
var translationFiles = [];
|
||||
var languageList = [];
|
||||
i18n.getPluginTranslationDetails(pluginTranslationPath, translationFiles, languageList);
|
||||
return languageList;
|
||||
}
|
||||
|
||||
function getPluginTranslationFiles(pluginName, pluginTranslationPath) {
|
||||
var translationFiles = [];
|
||||
var languageList = [];
|
||||
i18n.getPluginTranslationDetails(pluginTranslationPath, translationFiles, languageList);
|
||||
return translationFiles;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
[
|
||||
{
|
||||
"NO_SSL": "Dont run the DE dev server using HTTPS",
|
||||
"DEV": "Run the DE server with development mode defaults"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
[
|
||||
{
|
||||
"NO_SSL": "Dont run the dev server using HTTPS",
|
||||
"DEV": "Run the server with development mode defaults"
|
||||
}
|
||||
]
|
|
@ -0,0 +1,6 @@
|
|||
[
|
||||
{
|
||||
"NO_RUN_SERVER": "Dont run the dev server",
|
||||
"HOME": "Run along home now!"
|
||||
}
|
||||
]
|
Loading…
Add table
Add a link
Reference in a new issue