From c8ec053bb48fa424c9e54b01b26784900906c685 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 20 Sep 2021 16:51:06 +0200 Subject: [PATCH] gulp + locales New gulp task ``gulp locales`` - also part of ``gulp default`` - updates all locale files based on the master file w2locale.js Moved locale related settings from w2utils.js to w2locale.js - this is now basically the master English (en-us) translations file. Added current date string to gulp's w2ui header. Changed line breaks in locale file from CRLF to LF. Added missing German translations. --- gulpfile.js | 66 ++++++++++++++++++++--- src/locale/de-de.json | 22 ++++---- src/w2compat.js | 6 ++- src/w2grid.js | 2 +- src/w2locale.js | 119 +++++++++++++++++++++++++++++++++++++++++ src/w2utils.js | 121 +++--------------------------------------- 6 files changed, 200 insertions(+), 136 deletions(-) create mode 100644 src/w2locale.js diff --git a/gulpfile.js b/gulpfile.js index 05368f16d..58f070c55 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,5 +1,5 @@ +/* eslint-env node */ const gulp = require('gulp') -const { exec } = require('child_process') const header = require('gulp-header') const iconfont = require('gulp-iconfont') const less = require('gulp-less') @@ -7,11 +7,12 @@ const cleanCSS = require('gulp-clean-css') const uglify = require('gulp-uglify') const concat = require('gulp-concat') const rename = require('gulp-rename') -const babel = require('gulp-babel') const replace = require('gulp-replace') const del = require('del') +// const babel = require('gulp-babel') +// const { exec } = require('child_process') const comments = { - w2ui : '/* w2ui 2.0.x (nightly) (c) http://w2ui.com, vitmalina@gmail.com */\n' + w2ui : '/* w2ui 2.0.x (nightly) ('+ (new Date()).toLocaleDateString('en-us') +') (c) http://w2ui.com, vitmalina@gmail.com */\n' } let tasks = { @@ -48,6 +49,7 @@ let tasks = { return gulp .src([ 'src/w2event.js', // order of files is important + 'src/w2locale.js', 'src/w2utils.js', 'src/w2grid.js', 'src/w2layout.js', @@ -67,6 +69,7 @@ let tasks = { build(cb) { gulp.src([ 'src/w2event.js', // order of files is important + 'src/w2locale.js', 'src/w2utils.js', 'src/w2grid.js', 'src/w2layout.js', @@ -79,7 +82,7 @@ let tasks = { 'src/w2compat.js' // must be last ]) .pipe(concat('w2ui.js')) - .pipe(replace(/^import.*'$\n|^export.*}$\n/gm, '')) + .pipe(replace(/^(import.*'|export.*}|module\.exports.*})$\n/gm, '')) .pipe(replace('\n\n', '\n')) // .pipe(babel()) .pipe(header(comments.w2ui)) @@ -137,7 +140,7 @@ let tasks = {

w2ui-font $count

` let json = [] - let prom = gulp.src(['src/less/icons/svg/*.svg']) + gulp.src(['src/less/icons/svg/*.svg']) .pipe(iconfont({ startUnicode: 65, fontName: 'w2ui-font', @@ -182,12 +185,61 @@ let tasks = { gulp.watch(['src/**/*.js'], tasks.pack) // only packs dist/w2ui.js gulp.watch(['src/less/**/*.less'], tasks.less) gulp.watch(['src/less/icons/svg/*.svg'], tasks.icons) - } + }, + + locales(cb) { + const fs = require('fs') + const path = require('path') + const isPrimitive = obj => obj === null || [ 'string', 'number', 'boolean' ].includes( typeof obj ) + const isArrayOfPrimitive = obj => Array.isArray( obj ) && obj.every( isPrimitive ) + const format = arr => + `^^^[ ${ + arr.map( val => JSON.stringify( val ) ).join( ', ' ) + } ]` + const replacer = ( key, value ) => isArrayOfPrimitive( value ) ? format( value ) : value + const expand = str => str.replace( + /(?:"\^\^\^)(\[ .* \])(?:\")/g, ( match, a ) => + a.replace( /\\"/g, '"' ) + ) + const stringify = (obj, space=4) => expand( JSON.stringify( obj, replacer, space ) ) + function process_obj(m, o) { + Object.keys(o).forEach(k => { + if(typeof m[k] === 'undefined') delete o[k] + }) + for (const [k, v] of Object.entries(m)) { + if(typeof o[k] === 'undefined') o[k] = v + if(typeof v === 'object' && Object.keys(o[k]).length) o[k] = process_obj(v, o[k]) + } + return Object.assign(m, o) + } + function process_locales() { + const master = require('./src/w2locale.cjs').w2locale + const dir_locales = './src/locale' + fs.readdir(dir_locales, (err, files) => { + files.forEach(file => { + let m = JSON.parse(JSON.stringify(master)) + let filepath = path.join(dir_locales, file) + let o = JSON.parse( fs.readFileSync(filepath) ) + fs.writeFileSync(filepath, stringify(process_obj(m, o)) + '\n') + }) + }) + } + gulp.src(['src/w2locale.js']) + .pipe(replace(/^export {/gm, 'module.exports = {')) + .pipe(concat('w2locale.cjs')) + .pipe(gulp.dest('src/')) + .on('end', () => { + process_locales() + del('./src/w2locale.cjs') + cb() + }) + }, } -exports.default = gulp.series(tasks.clean, tasks.less, tasks.build) +exports.default = gulp.series(tasks.clean, tasks.less, tasks.locales, tasks.build) exports.build = tasks.build exports.dev = tasks.watch exports.clean = tasks.clean exports.less = gulp.series(tasks.clean, tasks.less) exports.icons = gulp.series(tasks.icons, tasks.less) +exports.locales = tasks.locales diff --git a/src/locale/de-de.json b/src/locale/de-de.json index 0ffc7b27e..99790eec3 100644 --- a/src/locale/de-de.json +++ b/src/locale/de-de.json @@ -23,7 +23,7 @@ "All Fields": "Alle Felder", "All": "All", "Any": "Any", - "Are you sure you want to delete ${count} ${records}?": "Are you sure you want to delete ${count} ${records}?", + "Are you sure you want to delete ${count} ${records}?": "Wollen Sie wirklich ${count} ${records} löschen?", "Attach files by dragging and dropping or Click to Select": "Dateien per Drag&Drop hinzufügen oder per Mausklick auswählen", "before": "vor", "begins with": "beginnt mit", @@ -40,7 +40,7 @@ "Current Date & Time": "Aktuelles Datum & Uhrzeit", "Delete selected records": "Ausgewählte Elemente löschen", "Delete": "Löschen", - "Do you want to delete search item \"${item}\"?": "Do you want to delete search item \"${item}\"?", + "Do you want to delete search item \"${item}\"?": "Wollen Sie \"${item}\" aus dem Suchverlauf löschen?", "Edit selected record": "Ausgewähltes Element editieren", "Edit": "Editieren", "Empty list": "Leere Liste", @@ -53,10 +53,10 @@ "is": "ist", "less than": "kleiner", "Line #": "Zeile #", - "Load ${count} more...": "Load ${count} more...", + "Load ${count} more...": "Lade ${count} mehr...", "Loading...": "Lädt ...", - "Maximum number of files is ${count}": "Maximum number of files is ${count}", - "Maximum total size is ${count}": "Maximum total size is ${count}", + "Maximum number of files is ${count}": "Maximale Anzahl an Dateien beträgt ${count}", + "Maximum total size is ${count}": "Maximale Größe beträgt ${count}", "Modified": "Geändert", "more than": "größer", "Multiple Fields": "Mehrere Felder", @@ -77,8 +77,8 @@ "of": "von", "Ok": "Ok", "Record ID": "Zeilen ID", - "record": "record", - "records": "records", + "record": "Eintrag", + "records": "Einträge", "Refreshing...": "Aktualisiere...", "Reload data in the list": "Liste aktualisieren", "Remove": "Entfernen", @@ -90,19 +90,19 @@ "Save changed records": "Geänderte Elemente speichern", "Save Grid State": "Grid-Einstellungen speichern", "Save": "Speichern", - "Saved Searches": "Saved Searches", + "Saved Searches": "Suchverlauf", "Saving...": "Speichere...", - "Search took ${count} seconds": "Search took ${count} seconds", + "Search took ${count} seconds": "Suche benötigte ${count} Sekunden", "Search": "Suchen", "Select Hour": "Stunde wählen", "Select Minute": "Minute wählen", "selected": "ausgewählt", - "Server Response ${count} seconds": "Server Response ${count} seconds", + "Server Response ${count} seconds": "Server Antwort benötigte ${count} Sekunden", "Show/hide columns": "Spalten zeigen/verbergen", "Show": "Zeigen", "Size": "Größe", "Skip": "Überspringe", - "Sorting took ${count} seconds": "Sorting took ${count} seconds", + "Sorting took ${count} seconds": "Sortieren benötigte ${count} Sekunden", "Type to search...": "Suchen...", "Type": "Typ", "Yes": "Ja", diff --git a/src/w2compat.js b/src/w2compat.js index 9e3d0e628..e1e220891 100644 --- a/src/w2compat.js +++ b/src/w2compat.js @@ -1,3 +1,4 @@ +import { w2locale } from './w2locale.js' import { w2ui, w2utils } from './w2utils.js' import { w2popup, w2alert, w2confirm, w2prompt } from './w2popup.js' import { w2field, addType, removeType } from './w2field.js' @@ -140,7 +141,7 @@ import { w2toolbar } from './w2toolbar.js' left : 0, // delta for left coordinate top : 0, // delta for top coordinate maxWidth : null, // max width - style : '', // adition style for the tag + style : '', // additional style for the tag css : {}, // add css for input when tag is shown className : '', // add class bubble inputClass : '', // add class for input when tag is shown @@ -1159,7 +1160,7 @@ import { w2toolbar } from './w2toolbar.js' transparent: true } if (options.onSelect == null && callBack != null) options.onSelect = callBack - // add remove transarent color + // add remove transparent color if (options.transparent && pal[0][1] == '333333') { pal[0].splice(1, 1) pal[0].push('') @@ -1500,6 +1501,7 @@ import { w2toolbar } from './w2toolbar.js' } })(self, { w2ui, + w2locale, w2utils, w2popup, w2alert, diff --git a/src/w2grid.js b/src/w2grid.js index 88baf2d78..d9eed2290 100644 --- a/src/w2grid.js +++ b/src/w2grid.js @@ -155,7 +155,7 @@ * - textSearch - deprecated in favor of defaultOperator * - grid.confirm * - grid.message returns a promise -* - search.type == 'text' can bave 'in' and 'not in' operators, then it will switch to enum +* - search.type == 'text' can have 'in' and 'not in' operators, then it will switch to enum * - removed msgDeleteBtn * ************************************************************************/ diff --git a/src/w2locale.js b/src/w2locale.js new file mode 100644 index 000000000..fd67b7479 --- /dev/null +++ b/src/w2locale.js @@ -0,0 +1,119 @@ +/************************************************************************ +* Part of w2ui 2.0 library +* These are the master locale settings that will be used by w2utils +************************************************************************/ + +const w2locale = { + 'locale' : 'en-us', + 'dateFormat' : 'm/d/yyyy', + 'timeFormat' : 'hh:mi pm', + 'datetimeFormat' : 'm/d/yyyy|hh:mi pm', + 'currencyPrefix' : '$', + 'currencySuffix' : '', + 'currencyPrecision' : 2, + 'groupSymbol' : ',', // aka "thousands separator" + 'decimalSymbol' : '.', + 'shortmonths' : ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + 'fullmonths' : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + 'shortdays' : ['M', 'T', 'W', 'T', 'F', 'S', 'S'], + 'fulldays' : ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'], + 'weekStarts' : 'M', // can be "M" for Monday or "S" for Sunday + 'phrases' : { // keep these up-to-date and in sorted order + '${count} letters or more...': '${count} letters or more...', + 'Add new record': 'Add new record', + 'Add New': 'Add New', + 'Advanced Search': 'Advanced Search', + 'after': 'after', + 'AJAX error. See console for more details.': 'AJAX error. See console for more details.', + 'All Fields': 'All Fields', + 'All': 'All', + 'Any': 'Any', + 'Are you sure you want to delete ${count} ${records}?': 'Are you sure you want to delete ${count} ${records}?', + 'Attach files by dragging and dropping or Click to Select': 'Attach files by dragging and dropping or Click to Select', + 'before': 'before', + 'begins with': 'begins with', + 'begins': 'begins', + 'between': 'between', + 'buffered': 'buffered', + 'Cancel': 'Cancel', + 'Close': 'Close', + 'Column': 'Column', + 'Confirmation': 'Confirmation', + 'contains': 'contains', + 'Copied': 'Copied', + 'Copy to clipboard': 'Copy to clipboard', + 'Current Date & Time': 'Current Date & Time', + 'Delete selected records': 'Delete selected records', + 'Delete': 'Delete', + 'Do you want to delete search item "${item}"?': 'Do you want to delete search item "${item}"?', + 'Edit selected record': 'Edit selected record', + 'Edit': 'Edit', + 'Empty list': 'Empty list', + 'ends with': 'ends with', + 'ends': 'ends', + 'Field should be at least ${count} characters.': 'Field should be at least ${count} characters.', + 'Hide': 'Hide', + 'in': 'in', + 'is not': 'is not', + 'is': 'is', + 'less than': 'less than', + 'Line #': 'Line #', + 'Load ${count} more...': 'Load ${count} more...', + 'Loading...': 'Loading...', + 'Maximum number of files is ${count}': 'Maximum number of files is ${count}', + 'Maximum total size is ${count}': 'Maximum total size is ${count}', + 'Modified': 'Modified', + 'more than': 'more than', + 'Multiple Fields': 'Multiple Fields', + 'Name': 'Name', + 'No items found': 'No items found', + 'No matches': 'No matches', + 'No': 'No', + 'none': 'none', + 'Not a float': 'Not a float', + 'Not a hex number': 'Not a hex number', + 'Not a valid date': 'Not a valid date', + 'Not a valid email': 'Not a valid email', + 'Not alpha-numeric': 'Not alpha-numeric', + 'Not an integer': 'Not an integer', + 'Not in money format': 'Not in money format', + 'not in': 'not in', + 'Notification': 'Notification', + 'of': 'of', + 'Ok': 'Ok', + 'Record ID': 'Record ID', + 'record': 'record', + 'records': 'records', + 'Refreshing...': 'Refreshing...', + 'Reload data in the list': 'Reload data in the list', + 'Remove': 'Remove', + 'Request aborted.': 'Request aborted.', + 'Required field': 'Required field', + 'Reset': 'Reset', + 'Restore Default State': 'Restore Default State', + 'Returned data is not in valid JSON format.': 'Returned data is not in valid JSON format.', + 'Save changed records': 'Save changed records', + 'Save Grid State': 'Save Grid State', + 'Save': 'Save', + 'Saved Searches': 'Saved Searches', + 'Saving...': 'Saving...', + 'Search took ${count} seconds': 'Search took ${count} seconds', + 'Search': 'Search', + 'Select Hour': 'Select Hour', + 'Select Minute': 'Select Minute', + 'selected': 'selected', + 'Server Response ${count} seconds': 'Server Response ${count} seconds', + 'Show/hide columns': 'Show/hide columns', + 'Show': 'Show', + 'Size': 'Size', + 'Skip': 'Skip', + 'Sorting took ${count} seconds': 'Sorting took ${count} seconds', + 'Type to search...': 'Type to search...', + 'Type': 'Type', + 'Yes': 'Yes', + 'Yesterday': 'Yesterday', + 'Your remote data source record count has changed, reloading from the first record.': 'Your remote data source record count has changed, reloading from the first record.' + } +} + +export { w2locale } diff --git a/src/w2utils.js b/src/w2utils.js index 89d466837..57129c0ce 100644 --- a/src/w2utils.js +++ b/src/w2utils.js @@ -18,129 +18,20 @@ * ************************************************/ import { w2event } from './w2event.js' +import { w2locale } from './w2locale.js' let w2ui = {} let w2utils = (($) => { let tmp = {} // for some temp variables return { version : '2.0.x', - settings : { - 'locale' : 'en-us', - 'dateFormat' : 'm/d/yyyy', - 'timeFormat' : 'hh:mi pm', - 'datetimeFormat' : 'm/d/yyyy|hh:mi pm', - 'currencyPrefix' : '$', - 'currencySuffix' : '', - 'currencyPrecision' : 2, - 'groupSymbol' : ',', // aka "thousands separator" - 'decimalSymbol' : '.', - 'shortmonths' : ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - 'fullmonths' : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], - 'shortdays' : ['M', 'T', 'W', 'T', 'F', 'S', 'S'], - 'fulldays' : ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'], - 'weekStarts' : 'M', // can be "M" for Monday or "S" for Sunday - 'phrases' : { // keep these up-to-date and in sorted order - '${count} letters or more...': '${count} letters or more...', - 'Add new record': 'Add new record', - 'Add New': 'Add New', - 'Advanced Search': 'Advanced Search', - 'after': 'after', - 'AJAX error. See console for more details.': 'AJAX error. See console for more details.', - 'All Fields': 'All Fields', - 'All': 'All', - 'Any': 'Any', - 'Are you sure you want to delete ${count} ${records}?': 'Are you sure you want to delete ${count} ${records}?', - 'Attach files by dragging and dropping or Click to Select': 'Attach files by dragging and dropping or Click to Select', - 'before': 'before', - 'begins with': 'begins with', - 'begins': 'begins', - 'between': 'between', - 'buffered': 'buffered', - 'Cancel': 'Cancel', - 'Close': 'Close', - 'Column': 'Column', - 'Confirmation': 'Confirmation', - 'contains': 'contains', - 'Copied': 'Copied', - 'Copy to clipboard': 'Copy to clipboard', - 'Current Date & Time': 'Current Date & Time', - 'Delete selected records': 'Delete selected records', - 'Delete': 'Delete', - 'Do you want to delete search item "${item}"?': 'Do you want to delete search item "${item}"?', - 'Edit selected record': 'Edit selected record', - 'Edit': 'Edit', - 'Empty list': 'Empty list', - 'ends with': 'ends with', - 'ends': 'ends', - 'Field should be at least ${count} characters.': 'Field should be at least ${count} characters.', - 'Hide': 'Hide', - 'in': 'in', - 'is not': 'is not', - 'is': 'is', - 'less than': 'less than', - 'Line #': 'Line #', - 'Load ${count} more...': 'Load ${count} more...', - 'Loading...': 'Loading...', - 'Maximum number of files is ${count}': 'Maximum number of files is ${count}', - 'Maximum total size is ${count}': 'Maximum total size is ${count}', - 'Modified': 'Modified', - 'more than': 'more than', - 'Multiple Fields': 'Multiple Fields', - 'Name': 'Name', - 'No items found': 'No items found', - 'No matches': 'No matches', - 'No': 'No', - 'none': 'none', - 'Not a float': 'Not a float', - 'Not a hex number': 'Not a hex number', - 'Not a valid date': 'Not a valid date', - 'Not a valid email': 'Not a valid email', - 'Not alpha-numeric': 'Not alpha-numeric', - 'Not an integer': 'Not an integer', - 'Not in money format': 'Not in money format', - 'not in': 'not in', - 'Notification': 'Notification', - 'of': 'of', - 'Ok': 'Ok', - 'Record ID': 'Record ID', - 'record': 'record', - 'records': 'records', - 'Refreshing...': 'Refreshing...', - 'Reload data in the list': 'Reload data in the list', - 'Remove': 'Remove', - 'Request aborted.': 'Request aborted.', - 'Required field': 'Required field', - 'Reset': 'Reset', - 'Restore Default State': 'Restore Default State', - 'Returned data is not in valid JSON format.': 'Returned data is not in valid JSON format.', - 'Save changed records': 'Save changed records', - 'Save Grid State': 'Save Grid State', - 'Save': 'Save', - 'Saved Searches': 'Saved Searches', - 'Saving...': 'Saving...', - 'Search took ${count} seconds': 'Search took ${count} seconds', - 'Search': 'Search', - 'Select Hour': 'Select Hour', - 'Select Minute': 'Select Minute', - 'selected': 'selected', - 'Server Response ${count} seconds': 'Server Response ${count} seconds', - 'Show/hide columns': 'Show/hide columns', - 'Show': 'Show', - 'Size': 'Size', - 'Skip': 'Skip', - 'Sorting took ${count} seconds': 'Sorting took ${count} seconds', - 'Type to search...': 'Type to search...', - 'Type': 'Type', - 'Yes': 'Yes', - 'Yesterday': 'Yesterday', - 'Your remote data source record count has changed, reloading from the first record.': 'Your remote data source record count has changed, reloading from the first record.' - }, + settings : $.extend(true, {}, w2locale, { 'dataType' : 'HTTPJSON', // can be HTTP, HTTPJSON, RESTFULL, RESTFULLJSON, JSON (case sensitive) 'dateStartYear' : 1950, // start year for date-picker 'dateEndYear' : 2030, // end year for date picker 'macButtonOrder' : false, // if true, Yes on the right side 'warn_missing_translation' : true, // call console.warn if lang() encounters a missing translation - }, + }), isBin, isInt, isFloat, @@ -1268,7 +1159,7 @@ let w2utils = (($) => { if (options.originalWidth < 0) options.width = pWidth + options.originalWidth * 2 // x 2 because there is left and right margin let head = $(where.box).find(where.title) - // if some messages are closing, insta close them + // if some messages are closing, instantly close them let $tmp = $(where.box).find('.w2ui-message.w2ui-closing') if ($(where.box).find('.w2ui-message.w2ui-closing').length > 0) { clearTimeout(closeTimer) @@ -1471,7 +1362,7 @@ let w2utils = (($) => { // if the locale is an object, not a string, than we assume it's a if (typeof locale !== 'string' ) { - w2utils.settings = $.extend(true, w2utils.settings, locale) + w2utils.settings = $.extend(true, {}, w2utils.settings, w2locale, locale) return } @@ -1486,7 +1377,7 @@ let w2utils = (($) => { type : 'GET', dataType : 'JSON', success(data, status, xhr) { - w2utils.settings = $.extend(true, w2utils.settings, data) + w2utils.settings = $.extend(true, {}, w2utils.settings, w2locale, data) if (typeof callBack === 'function') callBack() }, error(xhr, status, msg) {