uppy/packages/@uppy/utils/src/Translator.js
Artur Paikin 5079d98584
dashboard: 2020 redesign 🍿 (#2015)
* ProviderViews: Improve Instagram’s “video thumbnail”

* Update all provider icons to nicer round ones

* Change “drop files” copy depending on number of acquirers and Dashboard width

* Translator: support multiple components in options

When the source contains multiple placeholders for interpolation, we should ignore chunks that are not strings, because those can be JSX objects and will be otherwise incorrectly turned into strings.

Without this condition we’d get this: [object Object] hello [object Object] my <button>

* Remove unused locale strings

* Rever renderSingleInlineProvider, use Browse button instead of link, tweak styles

* Try “Browse My Device” button

* Introduce “Dark Mode“: new Dashboard option 'theme': 'light', 'dark' or 'auto'

* Refactor to also add uninstall/removeListener for the darkModeMediaQuery; remove all bindings in favor of class properties

* More dark mode styles: Providers, FileCard, tweaking focus, inputs, etc

* My Device: mobile and desktop icons

* add isMobileDevice capability, very simple detection

* More dark mode styles

* refactor

* switch back to single simple my device icon

* chrome 78 for android doesn’t support document.querySelector 👌

* nobr --> span white-space: nowrap

* Major style tweaks for mobile provider list, show dashed borders only when DnD is supported

* Add color after “import from”

just for Russian for now, because I’m thinking if this should be a part of the language string or html? @goto-bus-stop @kvz, what do you think?

* improve isMobileDevice, add tests

* don’t set the isMobileDevice capability in core for now

* add checks for typeof window !== 'undefined', otherwise fails in Node/RN

* update locales

* refactor renderDropFilesSubtitle
2020-03-24 18:05:11 +01:00

142 lines
4.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const has = require('./hasProperty')
/**
* Translates strings with interpolation & pluralization support.
* Extensible with custom dictionaries and pluralization functions.
*
* Borrows heavily from and inspired by Polyglot https://github.com/airbnb/polyglot.js,
* basically a stripped-down version of it. Differences: pluralization functions are not hardcoded
* and can be easily added among with dictionaries, nested objects are used for pluralization
* as opposed to `||||` delimeter
*
* Usage example: `translator.translate('files_chosen', {smart_count: 3})`
*/
module.exports = class Translator {
/**
* @param {object|Array<object>} locales - locale or list of locales.
*/
constructor (locales) {
this.locale = {
strings: {},
pluralize: function (n) {
if (n === 1) {
return 0
}
return 1
}
}
if (Array.isArray(locales)) {
locales.forEach((locale) => this._apply(locale))
} else {
this._apply(locales)
}
}
_apply (locale) {
if (!locale || !locale.strings) {
return
}
const prevLocale = this.locale
this.locale = Object.assign({}, prevLocale, {
strings: Object.assign({}, prevLocale.strings, locale.strings)
})
this.locale.pluralize = locale.pluralize || prevLocale.pluralize
}
/**
* Takes a string with placeholder variables like `%{smart_count} file selected`
* and replaces it with values from options `{smart_count: 5}`
*
* @license https://github.com/airbnb/polyglot.js/blob/master/LICENSE
* taken from https://github.com/airbnb/polyglot.js/blob/master/lib/polyglot.js#L299
*
* @param {string} phrase that needs interpolation, with placeholders
* @param {object} options with values that will be used to replace placeholders
* @returns {string} interpolated
*/
interpolate (phrase, options) {
const { split, replace } = String.prototype
const dollarRegex = /\$/g
const dollarBillsYall = '$$$$'
let interpolated = [phrase]
for (const arg in options) {
if (arg !== '_' && has(options, arg)) {
// Ensure replacement value is escaped to prevent special $-prefixed
// regex replace tokens. the "$$$$" is needed because each "$" needs to
// be escaped with "$" itself, and we need two in the resulting output.
var replacement = options[arg]
if (typeof replacement === 'string') {
replacement = replace.call(options[arg], dollarRegex, dollarBillsYall)
}
// We create a new `RegExp` each time instead of using a more-efficient
// string replace so that the same argument can be replaced multiple times
// in the same phrase.
interpolated = insertReplacement(interpolated, new RegExp('%\\{' + arg + '\\}', 'g'), replacement)
}
}
return interpolated
function insertReplacement (source, rx, replacement) {
const newParts = []
source.forEach((chunk) => {
// When the source contains multiple placeholders for interpolation,
// we should ignore chunks that are not strings, because those
// can be JSX objects and will be otherwise incorrectly turned into strings.
// Without this condition wed get this: [object Object] hello [object Object] my <button>
if (typeof chunk !== 'string') {
return newParts.push(chunk)
}
split.call(chunk, rx).forEach((raw, i, list) => {
if (raw !== '') {
newParts.push(raw)
}
// Interlace with the `replacement` value
if (i < list.length - 1) {
newParts.push(replacement)
}
})
})
return newParts
}
}
/**
* Public translate method
*
* @param {string} key
* @param {object} options with values that will be used later to replace placeholders in string
* @returns {string} translated (and interpolated)
*/
translate (key, options) {
return this.translateArray(key, options).join('')
}
/**
* Get a translation and return the translated and interpolated parts as an array.
*
* @param {string} key
* @param {object} options with values that will be used to replace placeholders
* @returns {Array} The translated and interpolated parts, in order.
*/
translateArray (key, options) {
const string = this.locale.strings[key]
const hasPluralForms = typeof string === 'object'
if (hasPluralForms) {
if (options && typeof options.smart_count !== 'undefined') {
const plural = this.locale.pluralize(options.smart_count)
return this.interpolate(string[plural], options)
} else {
throw new Error('Attempted to use a string with plural forms, but no value was given for %{smart_count}')
}
}
return this.interpolate(string, options)
}
}