From 786ffdc6cdabc15fd8e50240f662ea11e67ef5cc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 5 Sep 2020 23:57:29 +0000 Subject: [PATCH] chore: v5.0.1 release --- build/index.cjs | 200 +++++++++++++++++++++++++++++ build/index.cjs.d.ts | 18 +++ build/lib/cjs.d.ts | 10 ++ build/lib/cjs.js | 6 + build/lib/index.d.ts | 26 ++++ build/lib/index.js | 171 ++++++++++++++++++++++++ build/lib/platform-shims/node.d.ts | 13 ++ build/lib/platform-shims/node.js | 19 +++ 8 files changed, 463 insertions(+) create mode 100644 build/index.cjs create mode 100644 build/index.cjs.d.ts create mode 100644 build/lib/cjs.d.ts create mode 100644 build/lib/cjs.js create mode 100644 build/lib/index.d.ts create mode 100644 build/lib/index.js create mode 100644 build/lib/platform-shims/node.d.ts create mode 100644 build/lib/platform-shims/node.js diff --git a/build/index.cjs b/build/index.cjs new file mode 100644 index 00000000..ed709705 --- /dev/null +++ b/build/index.cjs @@ -0,0 +1,200 @@ +'use strict'; + +var fs = require('fs'); +var util = require('util'); +var path = require('path'); + +let shim; +class Y18N { + constructor(opts) { + // configurable options. + opts = opts || {}; + this.directory = opts.directory || './locales'; + this.updateFiles = typeof opts.updateFiles === 'boolean' ? opts.updateFiles : true; + this.locale = opts.locale || 'en'; + this.fallbackToLanguage = typeof opts.fallbackToLanguage === 'boolean' ? opts.fallbackToLanguage : true; + // internal stuff. + this.cache = {}; + this.writeQueue = []; + } + __(...args) { + if (typeof arguments[0] !== 'string') { + return this._taggedLiteral(arguments[0], ...arguments); + } + const str = args.shift(); + let cb = function () { }; // start with noop. + if (typeof args[args.length - 1] === 'function') + cb = args.pop(); + cb = cb || function () { }; // noop. + if (!this.cache[this.locale]) + this._readLocaleFile(); + // we've observed a new string, update the language file. + if (!this.cache[this.locale][str] && this.updateFiles) { + this.cache[this.locale][str] = str; + // include the current directory and locale, + // since these values could change before the + // write is performed. + this._enqueueWrite({ + directory: this.directory, + locale: this.locale, + cb + }); + } + else { + cb(); + } + return shim.format.apply(shim.format, [this.cache[this.locale][str] || str].concat(args)); + } + __n() { + const args = Array.prototype.slice.call(arguments); + const singular = args.shift(); + const plural = args.shift(); + const quantity = args.shift(); + let cb = function () { }; // start with noop. + if (typeof args[args.length - 1] === 'function') + cb = args.pop(); + if (!this.cache[this.locale]) + this._readLocaleFile(); + let str = quantity === 1 ? singular : plural; + if (this.cache[this.locale][singular]) { + const entry = this.cache[this.locale][singular]; + str = entry[quantity === 1 ? 'one' : 'other']; + } + // we've observed a new string, update the language file. + if (!this.cache[this.locale][singular] && this.updateFiles) { + this.cache[this.locale][singular] = { + one: singular, + other: plural + }; + // include the current directory and locale, + // since these values could change before the + // write is performed. + this._enqueueWrite({ + directory: this.directory, + locale: this.locale, + cb + }); + } + else { + cb(); + } + // if a %d placeholder is provided, add quantity + // to the arguments expanded by util.format. + var values = [str]; + if (~str.indexOf('%d')) + values.push(quantity); + return shim.format.apply(shim.format, values.concat(args)); + } + setLocale(locale) { + this.locale = locale; + } + getLocale() { + return this.locale; + } + updateLocale(obj) { + if (!this.cache[this.locale]) + this._readLocaleFile(); + for (const key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + this.cache[this.locale][key] = obj[key]; + } + } + } + _taggedLiteral(parts, ...args) { + let str = ''; + parts.forEach(function (part, i) { + var arg = args[i + 1]; + str += part; + if (typeof arg !== 'undefined') { + str += '%s'; + } + }); + return this.__.apply(this, [str].concat([].slice.call(args, 1))); + } + _enqueueWrite(work) { + this.writeQueue.push(work); + if (this.writeQueue.length === 1) + this._processWriteQueue(); + } + _processWriteQueue() { + var _this = this; + var work = this.writeQueue[0]; + // destructure the enqueued work. + var directory = work.directory; + var locale = work.locale; + var cb = work.cb; + var languageFile = this._resolveLocaleFile(directory, locale); + var serializedLocale = JSON.stringify(this.cache[locale], null, 2); + shim.fs.writeFile(languageFile, serializedLocale, 'utf-8', function (err) { + _this.writeQueue.shift(); + if (_this.writeQueue.length > 0) + _this._processWriteQueue(); + cb(err); + }); + } + _readLocaleFile() { + var localeLookup = {}; + var languageFile = this._resolveLocaleFile(this.directory, this.locale); + try { + localeLookup = JSON.parse(shim.fs.readFileSync(languageFile, 'utf-8')); + } + catch (err) { + if (err instanceof SyntaxError) { + err.message = 'syntax error in ' + languageFile; + } + if (err.code === 'ENOENT') + localeLookup = {}; + else + throw err; + } + this.cache[this.locale] = localeLookup; + } + _resolveLocaleFile(directory, locale) { + var file = shim.resolve(directory, './', locale + '.json'); + if (this.fallbackToLanguage && !this._fileExistsSync(file) && ~locale.lastIndexOf('_')) { + // attempt fallback to language only + var languageFile = shim.resolve(directory, './', locale.split('_')[0] + '.json'); + if (this._fileExistsSync(languageFile)) + file = languageFile; + } + return file; + } + _fileExistsSync(file) { + return shim.exists(file); + } +} +function y18n(opts, _shim) { + shim = _shim; + const y18n = new Y18N(opts); + return { + __: y18n.__.bind(y18n), + __n: y18n.__n.bind(y18n), + setLocale: y18n.setLocale.bind(y18n), + getLocale: y18n.getLocale.bind(y18n), + updateLocale: y18n.updateLocale.bind(y18n), + locale: y18n.locale + }; +} + +var nodePlatformShim = { + fs: { + readFileSync: fs.readFileSync, + writeFile: fs.writeFile + }, + format: util.format, + resolve: path.resolve, + exists: (file) => { + try { + return fs.statSync(file).isFile(); + } + catch (err) { + return false; + } + } +}; + +const y18n$1 = (opts) => { + return y18n(opts, nodePlatformShim); +}; + +module.exports = y18n$1; diff --git a/build/index.cjs.d.ts b/build/index.cjs.d.ts new file mode 100644 index 00000000..cd5e9b5a --- /dev/null +++ b/build/index.cjs.d.ts @@ -0,0 +1,18 @@ +interface Y18NOpts { + directory?: string; + updateFiles?: boolean; + locale?: string; + fallbackToLanguage?: boolean; +} +interface Locale { + [key: string]: string; +} +declare const y18n$0: (opts: Y18NOpts) => { + __: (...args: (string | Function)[]) => string; + __n: () => any; + setLocale: (locale: string) => void; + getLocale: () => string; + updateLocale: (obj: Locale) => void; + locale: string; +}; +export = y18n$0; diff --git a/build/lib/cjs.d.ts b/build/lib/cjs.d.ts new file mode 100644 index 00000000..8c964f29 --- /dev/null +++ b/build/lib/cjs.d.ts @@ -0,0 +1,10 @@ +import { Y18NOpts } from './index.js'; +declare const y18n: (opts: Y18NOpts) => { + __: (...args: (string | Function)[]) => string; + __n: () => any; + setLocale: (locale: string) => void; + getLocale: () => string; + updateLocale: (obj: import("./index.js").Locale) => void; + locale: string; +}; +export default y18n; diff --git a/build/lib/cjs.js b/build/lib/cjs.js new file mode 100644 index 00000000..ff584709 --- /dev/null +++ b/build/lib/cjs.js @@ -0,0 +1,6 @@ +import { y18n as _y18n } from './index.js'; +import nodePlatformShim from './platform-shims/node.js'; +const y18n = (opts) => { + return _y18n(opts, nodePlatformShim); +}; +export default y18n; diff --git a/build/lib/index.d.ts b/build/lib/index.d.ts new file mode 100644 index 00000000..6805afbc --- /dev/null +++ b/build/lib/index.d.ts @@ -0,0 +1,26 @@ +export interface Y18NOpts { + directory?: string; + updateFiles?: boolean; + locale?: string; + fallbackToLanguage?: boolean; +} +export interface Locale { + [key: string]: string; +} +export interface PlatformShim { + fs: { + readFileSync: Function; + writeFile: Function; + }; + exists: Function; + format: Function; + resolve: Function; +} +export declare function y18n(opts: Y18NOpts, _shim: PlatformShim): { + __: (...args: (string | Function)[]) => string; + __n: () => any; + setLocale: (locale: string) => void; + getLocale: () => string; + updateLocale: (obj: Locale) => void; + locale: string; +}; diff --git a/build/lib/index.js b/build/lib/index.js new file mode 100644 index 00000000..1fb2b0de --- /dev/null +++ b/build/lib/index.js @@ -0,0 +1,171 @@ +let shim; +class Y18N { + constructor(opts) { + // configurable options. + opts = opts || {}; + this.directory = opts.directory || './locales'; + this.updateFiles = typeof opts.updateFiles === 'boolean' ? opts.updateFiles : true; + this.locale = opts.locale || 'en'; + this.fallbackToLanguage = typeof opts.fallbackToLanguage === 'boolean' ? opts.fallbackToLanguage : true; + // internal stuff. + this.cache = {}; + this.writeQueue = []; + } + __(...args) { + if (typeof arguments[0] !== 'string') { + return this._taggedLiteral(arguments[0], ...arguments); + } + const str = args.shift(); + let cb = function () { }; // start with noop. + if (typeof args[args.length - 1] === 'function') + cb = args.pop(); + cb = cb || function () { }; // noop. + if (!this.cache[this.locale]) + this._readLocaleFile(); + // we've observed a new string, update the language file. + if (!this.cache[this.locale][str] && this.updateFiles) { + this.cache[this.locale][str] = str; + // include the current directory and locale, + // since these values could change before the + // write is performed. + this._enqueueWrite({ + directory: this.directory, + locale: this.locale, + cb + }); + } + else { + cb(); + } + return shim.format.apply(shim.format, [this.cache[this.locale][str] || str].concat(args)); + } + __n() { + const args = Array.prototype.slice.call(arguments); + const singular = args.shift(); + const plural = args.shift(); + const quantity = args.shift(); + let cb = function () { }; // start with noop. + if (typeof args[args.length - 1] === 'function') + cb = args.pop(); + if (!this.cache[this.locale]) + this._readLocaleFile(); + let str = quantity === 1 ? singular : plural; + if (this.cache[this.locale][singular]) { + const entry = this.cache[this.locale][singular]; + str = entry[quantity === 1 ? 'one' : 'other']; + } + // we've observed a new string, update the language file. + if (!this.cache[this.locale][singular] && this.updateFiles) { + this.cache[this.locale][singular] = { + one: singular, + other: plural + }; + // include the current directory and locale, + // since these values could change before the + // write is performed. + this._enqueueWrite({ + directory: this.directory, + locale: this.locale, + cb + }); + } + else { + cb(); + } + // if a %d placeholder is provided, add quantity + // to the arguments expanded by util.format. + var values = [str]; + if (~str.indexOf('%d')) + values.push(quantity); + return shim.format.apply(shim.format, values.concat(args)); + } + setLocale(locale) { + this.locale = locale; + } + getLocale() { + return this.locale; + } + updateLocale(obj) { + if (!this.cache[this.locale]) + this._readLocaleFile(); + for (const key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + this.cache[this.locale][key] = obj[key]; + } + } + } + _taggedLiteral(parts, ...args) { + let str = ''; + parts.forEach(function (part, i) { + var arg = args[i + 1]; + str += part; + if (typeof arg !== 'undefined') { + str += '%s'; + } + }); + return this.__.apply(this, [str].concat([].slice.call(args, 1))); + } + _enqueueWrite(work) { + this.writeQueue.push(work); + if (this.writeQueue.length === 1) + this._processWriteQueue(); + } + _processWriteQueue() { + var _this = this; + var work = this.writeQueue[0]; + // destructure the enqueued work. + var directory = work.directory; + var locale = work.locale; + var cb = work.cb; + var languageFile = this._resolveLocaleFile(directory, locale); + var serializedLocale = JSON.stringify(this.cache[locale], null, 2); + shim.fs.writeFile(languageFile, serializedLocale, 'utf-8', function (err) { + _this.writeQueue.shift(); + if (_this.writeQueue.length > 0) + _this._processWriteQueue(); + cb(err); + }); + } + _readLocaleFile() { + var localeLookup = {}; + var languageFile = this._resolveLocaleFile(this.directory, this.locale); + try { + localeLookup = JSON.parse(shim.fs.readFileSync(languageFile, 'utf-8')); + } + catch (err) { + if (err instanceof SyntaxError) { + err.message = 'syntax error in ' + languageFile; + } + if (err.code === 'ENOENT') + localeLookup = {}; + else + throw err; + } + this.cache[this.locale] = localeLookup; + } + _resolveLocaleFile(directory, locale) { + var file = shim.resolve(directory, './', locale + '.json'); + if (this.fallbackToLanguage && !this._fileExistsSync(file) && ~locale.lastIndexOf('_')) { + // attempt fallback to language only + var languageFile = shim.resolve(directory, './', locale.split('_')[0] + '.json'); + if (this._fileExistsSync(languageFile)) + file = languageFile; + } + return file; + } + _fileExistsSync(file) { + return shim.exists(file); + } +} +export function y18n(opts, _shim) { + shim = _shim; + const y18n = new Y18N(opts); + return { + __: y18n.__.bind(y18n), + __n: y18n.__n.bind(y18n), + setLocale: y18n.setLocale.bind(y18n), + getLocale: y18n.getLocale.bind(y18n), + updateLocale: y18n.updateLocale.bind(y18n), + locale: y18n.locale + }; +} diff --git a/build/lib/platform-shims/node.d.ts b/build/lib/platform-shims/node.d.ts new file mode 100644 index 00000000..20b6ef9e --- /dev/null +++ b/build/lib/platform-shims/node.d.ts @@ -0,0 +1,13 @@ +/// +import { readFileSync, writeFile } from 'fs'; +import { format } from 'util'; +declare const _default: { + fs: { + readFileSync: typeof readFileSync; + writeFile: typeof writeFile; + }; + format: typeof format; + resolve: (...pathSegments: string[]) => string; + exists: (file: string) => boolean; +}; +export default _default; diff --git a/build/lib/platform-shims/node.js b/build/lib/platform-shims/node.js new file mode 100644 index 00000000..181208b8 --- /dev/null +++ b/build/lib/platform-shims/node.js @@ -0,0 +1,19 @@ +import { readFileSync, statSync, writeFile } from 'fs'; +import { format } from 'util'; +import { resolve } from 'path'; +export default { + fs: { + readFileSync, + writeFile + }, + format, + resolve, + exists: (file) => { + try { + return statSync(file).isFile(); + } + catch (err) { + return false; + } + } +};