diff --git a/bin/locale-packs.js b/bin/locale-packs.js
deleted file mode 100644
index ff58b27c76..0000000000
--- a/bin/locale-packs.js
+++ /dev/null
@@ -1,295 +0,0 @@
-const glob = require('glob')
-const { ESLint } = require('eslint')
-const chalk = require('chalk')
-const path = require('path')
-const dedent = require('dedent')
-const stringifyObject = require('stringify-object')
-const fs = require('fs')
-const Uppy = require('../packages/@uppy/core')
-
-const uppy = new Uppy()
-
-function getSources (pluginName) {
- const dependencies = {
- // because 'provider-views' doesn't have its own locale, it uses Core's defaultLocale
- core: ['provider-views'],
- }
-
- const globPath = path.join(__dirname, '..', 'packages', '@uppy', pluginName, 'lib', '**', '*.js')
- let contents = glob.sync(globPath).map((file) => {
- return fs.readFileSync(file, 'utf-8')
- })
-
- if (dependencies[pluginName]) {
- dependencies[pluginName].forEach((addPlugin) => {
- contents = contents.concat(getSources(addPlugin))
- })
- }
-
- return contents
-}
-
-function buildPluginsList () {
- const plugins = {}
- const sources = {}
-
- // Go over all uppy plugins, check if they are constructors
- // and instanciate them, check for defaultLocale property,
- // then add to plugins object
-
- const packagesGlobPath = path.join(__dirname, '..', 'packages', '@uppy', '*', 'package.json')
- const files = glob.sync(packagesGlobPath)
-
- console.log('--> Checked plugins could be instantiated and have defaultLocale in them:\n')
- for (const file of files) {
- const dirName = path.dirname(file)
- const pluginName = path.basename(dirName)
- if (pluginName === 'locales'
- || pluginName === 'react-native'
- || pluginName === 'vue'
- || pluginName === 'svelte'
- || pluginName === 'angular') {
- continue // eslint-disable-line no-continue
- }
- const Plugin = require(dirName) // eslint-disable-line global-require, import/no-dynamic-require
- let plugin
-
- // A few hacks to emulate browser environment because e.g.:
- // GoldenRetrieves calls upon MetaDataStore in the constructor, which uses localStorage
- // @TODO Consider rewriting constructors so they don't make imperative calls that rely on browser environment
- // (OR: just keep this browser mocking, if it's only causing issues for this script, it doesn't matter)
- global.location = { protocol: 'https' }
- global.navigator = { userAgent: '' }
- global.localStorage = {
- key: () => { },
- getItem: () => { },
- }
- global.window = {
- indexedDB: {
- open: () => { return {} },
- },
- }
- global.document = {
- createElement: () => {
- return { style: {} }
- },
- get body () { return this.createElement() },
- }
-
- try {
- if (pluginName === 'provider-views') {
- plugin = new Plugin(plugins['drag-drop'], {
- companionPattern: '',
- companionUrl: 'https://companion.uppy.io',
- })
- } else if (pluginName === 'store-redux') {
- plugin = new Plugin({ store: { dispatch: () => { } } })
- } else {
- plugin = new Plugin(uppy, {
- companionPattern: '',
- companionUrl: 'https://companion.uppy.io',
- params: {
- auth: {
- key: 'x',
- },
- },
- })
- }
- } catch (err) {
- if (err.message !== 'Plugin is not a constructor') {
- console.error(`--> While trying to instantiate plugin: ${pluginName}, this error was thrown: `)
- throw err
- }
- }
-
- if (plugin && plugin.defaultLocale) {
- console.log(`[x] Check plugin: ${pluginName}`)
- plugins[pluginName] = plugin
- sources[pluginName] = getSources(pluginName)
- } else {
- console.log(`[ ] Check plugin: ${pluginName}`)
- }
- }
-
- console.log('')
-
- return { plugins, sources }
-}
-
-function addLocaleToPack (localePack, plugin, pluginName) {
- const localeStrings = plugin.defaultLocale.strings
-
- for (const key of Object.keys(localeStrings)) {
- const valueInPlugin = JSON.stringify(localeStrings[key])
- const valueInPack = JSON.stringify(localePack[key])
-
- if (key in localePack && valueInPlugin !== valueInPack) {
- console.error(`⚠ Plugin ${chalk.magenta(pluginName)} has a duplicate key: ${chalk.magenta(key)}`)
- console.error(` Value in plugin: ${chalk.cyan(valueInPlugin)}`)
- console.error(` Value in pack : ${chalk.yellow(valueInPack)}`)
- console.error()
- throw new Error(`Duplicate locale key: '${key}'`)
- }
- localePack[key] = localeStrings[key] // eslint-disable-line no-param-reassign
- }
-}
-
-function checkForUnused (fileContents, pluginName, localePack) {
- const buff = fileContents.join('\n')
- for (const key of Object.keys(localePack)) {
- const regPat = new RegExp(`(i18n|i18nArray)\\([^\\)]*['\`"]${key}['\`"]`, 'g')
- if (!buff.match(regPat)) {
- console.error(`⚠ defaultLocale key: ${chalk.magenta(key)} not used in plugin: ${chalk.cyan(pluginName)}`)
- throw new Error(`Unused locale key: '${key}'`)
- }
- }
-}
-
-function sortObjectAlphabetically (obj) {
- return Object.fromEntries(Object.entries(obj).sort(([keyA], [keyB]) => keyA.localeCompare(keyB)))
-}
-
-function createTypeScriptLocale (plugin, pluginName) {
- const allowedStringTypes = Object.keys(plugin.defaultLocale.strings)
- .map(key => ` | '${key}'`)
- .join('\n')
-
- const pluginClassName = pluginName === 'core' ? 'Core' : plugin.id
- const localePath = path.join(__dirname, '..', 'packages', '@uppy', pluginName, 'types', 'generatedLocale.d.ts')
-
- const localeTypes = dedent`
- /* eslint-disable */
- import type { Locale } from '@uppy/core'
-
- type ${pluginClassName}Locale = Locale<
- ${allowedStringTypes}
- >
-
- export default ${pluginClassName}Locale
- `
-
- fs.writeFileSync(localePath, localeTypes)
-}
-
-async function build () {
- let localePack = {}
- const { plugins, sources } = buildPluginsList()
-
- for (const [pluginName, plugin] of Object.entries(plugins)) {
- addLocaleToPack(localePack, plugin, pluginName)
- }
-
- for (const [pluginName, plugin] of Object.entries(plugins)) {
- createTypeScriptLocale(plugin, pluginName)
- }
-
- localePack = sortObjectAlphabetically(localePack)
-
- for (const [pluginName, source] of Object.entries(sources)) {
- checkForUnused(source, pluginName, sortObjectAlphabetically(plugins[pluginName].defaultLocale.strings))
- }
-
- const prettyLocale = stringifyObject(localePack, {
- indent: ' ',
- singleQuotes: true,
- inlineCharacterLimit: 12,
- })
-
- const localeTemplatePath = path.join(__dirname, '..', 'packages', '@uppy', 'locales', 'template.js')
- const template = fs.readFileSync(localeTemplatePath, 'utf-8')
-
- const finalLocale = template.replace('en_US.strings = {}', `en_US.strings = ${prettyLocale}`)
-
- const localePackagePath = path.join(__dirname, '..', 'packages', '@uppy', 'locales', 'src', 'en_US.js')
-
- const linter = new ESLint({
- fix: true,
- })
-
- const [lintResult] = await linter.lintText(finalLocale, {
- filePath: localePackagePath,
- })
- fs.writeFileSync(localePackagePath, lintResult.output, 'utf8')
-
- console.log(`✅ Written '${localePackagePath}'`)
-}
-
-function test () {
- const leadingLocaleName = 'en_US'
-
- const followerLocales = {}
- const followerValues = {}
- const localePackagePath = path.join(__dirname, '..', 'packages', '@uppy', 'locales', 'src', '*.js')
- glob.sync(localePackagePath).forEach((localePath) => {
- const localeName = path.basename(localePath, '.js')
-
- // Builds array with items like: 'uploadingXFiles'
- // We do not check nested items because different languages may have different amounts of plural forms.
- // eslint-disable-next-line global-require, import/no-dynamic-require
- followerValues[localeName] = require(localePath).strings
- followerLocales[localeName] = Object.keys(followerValues[localeName])
- })
-
- // Take aside our leading locale: en_US
- const leadingLocale = followerLocales[leadingLocaleName]
- const leadingValues = followerValues[leadingLocaleName]
- delete followerLocales[leadingLocaleName]
-
- // Compare all follower Locales (RU, DE, etc) with our leader en_US
- const warnings = []
- const fatals = []
- for (const [followerName, followerLocale] of Object.entries(followerLocales)) {
- const missing = leadingLocale.filter((key) => !followerLocale.includes(key))
- const excess = followerLocale.filter((key) => !leadingLocale.includes(key))
-
- missing.forEach((key) => {
- // Items missing are a non-fatal warning because we don't want CI to bum out over all languages
- // as soon as we add some English
- let value = leadingValues[key]
- if (typeof value === 'object') {
- // For values with plural forms, just take the first one right now
- value = value[Object.keys(value)[0]]
- }
- warnings.push(`${chalk.cyan(followerName)} locale has missing string: '${chalk.red(key)}' that is present in ${chalk.cyan(leadingLocaleName)} with value: ${chalk.yellow(leadingValues[key])}`)
- })
- excess.forEach((key) => {
- // Items in excess are a fatal because we should clean up follower languages once we remove English strings
- fatals.push(`${chalk.cyan(followerName)} locale has excess string: '${chalk.yellow(key)}' that is not present in ${chalk.cyan(leadingLocaleName)}. `)
- })
- }
-
- if (warnings.length) {
- console.error('--> Locale warnings: ')
- console.error(warnings.join('\n'))
- console.error('')
- }
- if (fatals.length) {
- console.error('--> Locale fatal warnings: ')
- console.error(fatals.join('\n'))
- console.error('')
- process.exit(1)
- }
-
- if (!warnings.length && !fatals.length) {
- console.log(`--> All locale strings have matching keys ${chalk.green(': )')}`)
- console.log('')
- }
-}
-
-async function main () {
- console.warn('\n--> Make sure to run `npm run build:lib` for this locale script to work properly. ')
-
- const mode = process.argv[2]
- if (mode === 'build') {
- await build()
- } else if (mode === 'test') {
- test()
- } else {
- throw new Error("First argument must be either 'build' or 'test'")
- }
-}
-
-main().catch((err) => {
- console.error(err)
- process.exit(1)
-})
diff --git a/package.json b/package.json
index 24f41f738c..54eed56092 100644
--- a/package.json
+++ b/package.json
@@ -135,7 +135,7 @@
"build:angular": "yarn workspace @uppy/angular build:release",
"build:js": "npm-run-all build:lib build:companion build:locale-pack build:svelte build:angular build:bundle",
"build:lib": "yarn node ./bin/build-lib.js",
- "build:locale-pack": "yarn node --experimental-abortcontroller ./bin/locale-packs.js build",
+ "build:locale-pack": "yarn workspace locale-pack build && eslint packages/@uppy/locales/src/en_US.js --fix && yarn workspace locale-pack test unused",
"build": "npm-run-all --parallel build:js build:css --serial size",
"contributors:save": "yarn node ./bin/update-contributors.mjs",
"dev:browsersync": "yarn workspace @uppy-example/dev start",
@@ -156,7 +156,8 @@
"test:companion": "yarn workspace @uppy/companion test",
"test:endtoend:local": "yarn workspace @uppy-tests/end2end test:endtoend:local",
"test:endtoend": "yarn workspace @uppy-tests/end2end test:endtoend",
- "test:locale-packs": "yarn node ./bin/locale-packs.js test",
+ "test:locale-packs:unused": "yarn workspace locale-pack test unused",
+ "test:locale-packs:warnings": "yarn workspace locale-pack test warnings",
"test:type": "yarn workspaces foreach -piv --include '@uppy/*' --exclude '@uppy/{angular,react-native,locales,companion,provider-views,robodog,svelte}' exec tsd",
"test:unit": "yarn run build:lib && jest --env jsdom",
"test:watch": "jest --env jsdom --watch",
diff --git a/packages/@uppy/aws-s3/src/index.js b/packages/@uppy/aws-s3/src/index.js
index b2949df241..512aa9722d 100644
--- a/packages/@uppy/aws-s3/src/index.js
+++ b/packages/@uppy/aws-s3/src/index.js
@@ -31,6 +31,8 @@ const { RequestClient } = require('@uppy/companion-client')
const MiniXHRUpload = require('./MiniXHRUpload')
const isXml = require('./isXml')
+const locale = require('./locale')
+
function resolveUrl (origin, link) {
return new URL(link, origin || undefined).toString()
}
@@ -108,11 +110,7 @@ module.exports = class AwsS3 extends BasePlugin {
this.id = this.opts.id || 'AwsS3'
this.title = 'AWS S3'
- this.defaultLocale = {
- strings: {
- timedOut: 'Upload stalled for %{seconds} seconds, aborting.',
- },
- }
+ this.defaultLocale = locale
const defaultOptions = {
timeout: 30 * 1000,
diff --git a/packages/@uppy/aws-s3/src/locale.js b/packages/@uppy/aws-s3/src/locale.js
new file mode 100644
index 0000000000..b043ff91c2
--- /dev/null
+++ b/packages/@uppy/aws-s3/src/locale.js
@@ -0,0 +1,5 @@
+module.exports = {
+ strings: {
+ timedOut: 'Upload stalled for %{seconds} seconds, aborting.',
+ },
+}
diff --git a/packages/@uppy/box/src/index.js b/packages/@uppy/box/src/index.js
index b0a6a4a7e3..064b0fa3f8 100644
--- a/packages/@uppy/box/src/index.js
+++ b/packages/@uppy/box/src/index.js
@@ -3,6 +3,8 @@ const { Provider } = require('@uppy/companion-client')
const { ProviderViews } = require('@uppy/provider-views')
const { h } = require('preact')
+const locale = require('./locale')
+
module.exports = class Box extends UIPlugin {
static VERSION = require('../package.json').version
@@ -32,11 +34,8 @@ module.exports = class Box extends UIPlugin {
pluginId: this.id,
})
- this.defaultLocale = {
- strings: {
- pluginNameBox: 'Box',
- },
- }
+ this.defaultLocale = locale
+
this.i18nInit()
this.title = this.i18n('pluginNameBox')
diff --git a/packages/@uppy/box/src/locale.js b/packages/@uppy/box/src/locale.js
new file mode 100644
index 0000000000..18e820dac2
--- /dev/null
+++ b/packages/@uppy/box/src/locale.js
@@ -0,0 +1,5 @@
+module.exports = {
+ strings: {
+ pluginNameBox: 'Box',
+ },
+}
diff --git a/packages/@uppy/core/src/Uppy.js b/packages/@uppy/core/src/Uppy.js
index 8a39ad27dc..100365f0c4 100644
--- a/packages/@uppy/core/src/Uppy.js
+++ b/packages/@uppy/core/src/Uppy.js
@@ -16,6 +16,8 @@ const supportsUploadProgress = require('./supportsUploadProgress')
const getFileName = require('./getFileName')
const { justErrorsLogger, debugLogger } = require('./loggers')
+const locale = require('./locale')
+
// Exported from here.
class RestrictionError extends Error {
constructor (...args) {
@@ -68,60 +70,7 @@ class Uppy {
* @param {object} opts — Uppy options
*/
constructor (opts) {
- this.defaultLocale = {
- strings: {
- addBulkFilesFailed: {
- 0: 'Failed to add %{smart_count} file due to an internal error',
- 1: 'Failed to add %{smart_count} files due to internal errors',
- },
- youCanOnlyUploadX: {
- 0: 'You can only upload %{smart_count} file',
- 1: 'You can only upload %{smart_count} files',
- },
- youHaveToAtLeastSelectX: {
- 0: 'You have to select at least %{smart_count} file',
- 1: 'You have to select at least %{smart_count} files',
- },
- exceedsSize: '%{file} exceeds maximum allowed size of %{size}',
- missingRequiredMetaField: 'Missing required meta fields',
- missingRequiredMetaFieldOnFile: 'Missing required meta fields in %{fileName}',
- inferiorSize: 'This file is smaller than the allowed size of %{size}',
- youCanOnlyUploadFileTypes: 'You can only upload: %{types}',
- noMoreFilesAllowed: 'Cannot add more files',
- noDuplicates: 'Cannot add the duplicate file \'%{fileName}\', it already exists',
- companionError: 'Connection with Companion failed',
- authAborted: 'Authentication aborted',
- companionUnauthorizeHint: 'To unauthorize to your %{provider} account, please go to %{url}',
- failedToUpload: 'Failed to upload %{file}',
- noInternetConnection: 'No Internet connection',
- connectedToInternet: 'Connected to the Internet',
- // Strings for remote providers
- noFilesFound: 'You have no files or folders here',
- selectX: {
- 0: 'Select %{smart_count}',
- 1: 'Select %{smart_count}',
- },
- allFilesFromFolderNamed: 'All files from folder %{name}',
- openFolderNamed: 'Open folder %{name}',
- cancel: 'Cancel',
- logOut: 'Log out',
- filter: 'Filter',
- resetFilter: 'Reset filter',
- loading: 'Loading...',
- authenticateWithTitle: 'Please authenticate with %{pluginName} to select files',
- authenticateWith: 'Connect to %{pluginName}',
- signInWithGoogle: 'Sign in with Google',
- searchImages: 'Search for images',
- enterTextToSearch: 'Enter text to search for images',
- backToSearch: 'Back to Search',
- emptyFolderAdded: 'No files were added from empty folder',
- folderAlreadyAdded: 'The folder "%{folder}" was already added',
- folderAdded: {
- 0: 'Added %{smart_count} file from %{folder}',
- 1: 'Added %{smart_count} files from %{folder}',
- },
- },
- }
+ this.defaultLocale = locale
const defaultOptions = {
id: 'uppy',
diff --git a/packages/@uppy/core/src/locale.js b/packages/@uppy/core/src/locale.js
new file mode 100644
index 0000000000..3423c9366a
--- /dev/null
+++ b/packages/@uppy/core/src/locale.js
@@ -0,0 +1,58 @@
+module.exports = {
+ strings: {
+ addBulkFilesFailed: {
+ 0: 'Failed to add %{smart_count} file due to an internal error',
+ 1: 'Failed to add %{smart_count} files due to internal errors',
+ },
+ youCanOnlyUploadX: {
+ 0: 'You can only upload %{smart_count} file',
+ 1: 'You can only upload %{smart_count} files',
+ },
+ youHaveToAtLeastSelectX: {
+ 0: 'You have to select at least %{smart_count} file',
+ 1: 'You have to select at least %{smart_count} files',
+ },
+ exceedsSize: '%{file} exceeds maximum allowed size of %{size}',
+ missingRequiredMetaField: 'Missing required meta fields',
+ missingRequiredMetaFieldOnFile:
+ 'Missing required meta fields in %{fileName}',
+ inferiorSize: 'This file is smaller than the allowed size of %{size}',
+ youCanOnlyUploadFileTypes: 'You can only upload: %{types}',
+ noMoreFilesAllowed: 'Cannot add more files',
+ noDuplicates:
+ "Cannot add the duplicate file '%{fileName}', it already exists",
+ companionError: 'Connection with Companion failed',
+ authAborted: 'Authentication aborted',
+ companionUnauthorizeHint:
+ 'To unauthorize to your %{provider} account, please go to %{url}',
+ failedToUpload: 'Failed to upload %{file}',
+ noInternetConnection: 'No Internet connection',
+ connectedToInternet: 'Connected to the Internet',
+ // Strings for remote providers
+ noFilesFound: 'You have no files or folders here',
+ selectX: {
+ 0: 'Select %{smart_count}',
+ 1: 'Select %{smart_count}',
+ },
+ allFilesFromFolderNamed: 'All files from folder %{name}',
+ openFolderNamed: 'Open folder %{name}',
+ cancel: 'Cancel',
+ logOut: 'Log out',
+ filter: 'Filter',
+ resetFilter: 'Reset filter',
+ loading: 'Loading...',
+ authenticateWithTitle:
+ 'Please authenticate with %{pluginName} to select files',
+ authenticateWith: 'Connect to %{pluginName}',
+ signInWithGoogle: 'Sign in with Google',
+ searchImages: 'Search for images',
+ enterTextToSearch: 'Enter text to search for images',
+ backToSearch: 'Back to Search',
+ emptyFolderAdded: 'No files were added from empty folder',
+ folderAlreadyAdded: 'The folder "%{folder}" was already added',
+ folderAdded: {
+ 0: 'Added %{smart_count} file from %{folder}',
+ 1: 'Added %{smart_count} files from %{folder}',
+ },
+ },
+}
diff --git a/packages/@uppy/dashboard/src/index.js b/packages/@uppy/dashboard/src/index.js
index da1e7988db..f40dcb39d0 100644
--- a/packages/@uppy/dashboard/src/index.js
+++ b/packages/@uppy/dashboard/src/index.js
@@ -14,6 +14,8 @@ const memoize = require('memoize-one').default || require('memoize-one')
const FOCUSABLE_ELEMENTS = require('@uppy/utils/lib/FOCUSABLE_ELEMENTS')
const DashboardUI = require('./components/Dashboard')
+const locale = require('./locale')
+
const TAB_KEY = 9
const ESC_KEY = 27
@@ -47,70 +49,7 @@ module.exports = class Dashboard extends UIPlugin {
this.type = 'orchestrator'
this.modalName = `uppy-Dashboard-${nanoid()}`
- this.defaultLocale = {
- strings: {
- closeModal: 'Close Modal',
- importFrom: 'Import from %{name}',
- addingMoreFiles: 'Adding more files',
- addMoreFiles: 'Add more files',
- dashboardWindowTitle: 'File Uploader Window (Press escape to close)',
- dashboardTitle: 'File Uploader',
- copyLinkToClipboardSuccess: 'Link copied to clipboard',
- copyLinkToClipboardFallback: 'Copy the URL below',
- copyLink: 'Copy link',
- back: 'Back',
- addMore: 'Add more',
- removeFile: 'Remove file %{file}',
- editFile: 'Edit file',
- editFileWithFilename: 'Edit file %{file}',
- editing: 'Editing %{file}',
- finishEditingFile: 'Finish editing file',
- save: 'Save',
- saveChanges: 'Save changes',
- cancel: 'Cancel',
- myDevice: 'My Device',
- dropPasteFiles: 'Drop files here or %{browseFiles}',
- dropPasteFolders: 'Drop files here or %{browseFolders}',
- dropPasteBoth: 'Drop files here, %{browseFiles} or %{browseFolders}',
- dropPasteImportFiles: 'Drop files here, %{browseFiles} or import from:',
- dropPasteImportFolders: 'Drop files here, %{browseFolders} or import from:',
- dropPasteImportBoth: 'Drop files here, %{browseFiles}, %{browseFolders} or import from:',
- importFiles: 'Import files from:',
- dropHint: 'Drop your files here',
- browseFiles: 'browse files',
- browseFolders: 'browse folders',
- uploadComplete: 'Upload complete',
- uploadPaused: 'Upload paused',
- resumeUpload: 'Resume upload',
- pauseUpload: 'Pause upload',
- retryUpload: 'Retry upload',
- cancelUpload: 'Cancel upload',
- xFilesSelected: {
- 0: '%{smart_count} file selected',
- 1: '%{smart_count} files selected',
- },
- uploadingXFiles: {
- 0: 'Uploading %{smart_count} file',
- 1: 'Uploading %{smart_count} files',
- },
- processingXFiles: {
- 0: 'Processing %{smart_count} file',
- 1: 'Processing %{smart_count} files',
- },
- recoveredXFiles: {
- 0: 'We could not fully recover 1 file. Please re-select it and resume the upload.',
- 1: 'We could not fully recover %{smart_count} files. Please re-select them and resume the upload.',
- },
- recoveredAllFiles: 'We restored all files. You can now resume the upload.',
- sessionRestored: 'Session restored',
- reSelect: 'Re-select',
- poweredBy: 'Powered by %{uppy}',
- missingRequiredMetaFields: {
- 0: 'Missing required meta field: %{fields}.',
- 1: 'Missing required meta fields: %{fields}.',
- },
- },
- }
+ this.defaultLocale = locale
// set default options
const defaultOptions = {
diff --git a/packages/@uppy/dashboard/src/locale.js b/packages/@uppy/dashboard/src/locale.js
new file mode 100644
index 0000000000..8030311d36
--- /dev/null
+++ b/packages/@uppy/dashboard/src/locale.js
@@ -0,0 +1,88 @@
+module.exports = {
+ strings: {
+ // When `inline: false`, used as the screen reader label for the button that closes the modal.
+ closeModal: 'Close Modal',
+ // Used as the screen reader label for the plus (+) button that shows the “Add more files” screen
+ addMoreFiles: 'Add more files',
+ addingMoreFiles: 'Adding more files',
+ // Used as the header for import panels, e.g., “Import from Google Drive”.
+ importFrom: 'Import from %{name}',
+ // When `inline: false`, used as the screen reader label for the dashboard modal.
+ dashboardWindowTitle: 'Uppy Dashboard Window (Press escape to close)',
+ // When `inline: true`, used as the screen reader label for the dashboard area.
+ dashboardTitle: 'Uppy Dashboard',
+ // Shown in the Informer when a link to a file was copied to the clipboard.
+ copyLinkToClipboardSuccess: 'Link copied to clipboard.',
+ // Used when a link cannot be copied automatically — the user has to select the text from the
+ // input element below this string.
+ copyLinkToClipboardFallback: 'Copy the URL below',
+ // Used as the hover title and screen reader label for buttons that copy a file link.
+ copyLink: 'Copy link',
+ back: 'Back',
+ // Used as the screen reader label for buttons that remove a file.
+ removeFile: 'Remove file',
+ // Used as the screen reader label for buttons that open the metadata editor panel for a file.
+ editFile: 'Edit file',
+ // Shown in the panel header for the metadata editor. Rendered as “Editing image.png”.
+ editing: 'Editing %{file}',
+ // Used as the screen reader label for the button that saves metadata edits and returns to the
+ // file list view.
+ finishEditingFile: 'Finish editing file',
+ saveChanges: 'Save changes',
+ // Used as the label for the tab button that opens the system file selection dialog.
+ myDevice: 'My Device',
+ dropHint: 'Drop your files here',
+ // Used as the hover text and screen reader label for file progress indicators when
+ // they have been fully uploaded.
+ uploadComplete: 'Upload complete',
+ uploadPaused: 'Upload paused',
+ // Used as the hover text and screen reader label for the buttons to resume paused uploads.
+ resumeUpload: 'Resume upload',
+ // Used as the hover text and screen reader label for the buttons to pause uploads.
+ pauseUpload: 'Pause upload',
+ // Used as the hover text and screen reader label for the buttons to retry failed uploads.
+ retryUpload: 'Retry upload',
+ // Used as the hover text and screen reader label for the buttons to cancel uploads.
+ cancelUpload: 'Cancel upload',
+ // Used in a title, how many files are currently selected
+ xFilesSelected: {
+ 0: '%{smart_count} file selected',
+ 1: '%{smart_count} files selected',
+ },
+ uploadingXFiles: {
+ 0: 'Uploading %{smart_count} file',
+ 1: 'Uploading %{smart_count} files',
+ },
+ processingXFiles: {
+ 0: 'Processing %{smart_count} file',
+ 1: 'Processing %{smart_count} files',
+ },
+ // The "powered by Uppy" link at the bottom of the Dashboard.
+ poweredBy: 'Powered by %{uppy}',
+ addMore: 'Add more',
+ editFileWithFilename: 'Edit file %{file}',
+ save: 'Save',
+ cancel: 'Cancel',
+ dropPasteFiles: 'Drop files here or %{browseFiles}',
+ dropPasteFolders: 'Drop files here or %{browseFolders}',
+ dropPasteBoth: 'Drop files here, %{browseFiles} or %{browseFolders}',
+ dropPasteImportFiles: 'Drop files here, %{browseFiles} or import from:',
+ dropPasteImportFolders: 'Drop files here, %{browseFolders} or import from:',
+ dropPasteImportBoth:
+ 'Drop files here, %{browseFiles}, %{browseFolders} or import from:',
+ importFiles: 'Import files from:',
+ browseFiles: 'browse files',
+ browseFolders: 'browse folders',
+ recoveredXFiles: {
+ 0: 'We could not fully recover 1 file. Please re-select it and resume the upload.',
+ 1: 'We could not fully recover %{smart_count} files. Please re-select them and resume the upload.',
+ },
+ recoveredAllFiles: 'We restored all files. You can now resume the upload.',
+ sessionRestored: 'Session restored',
+ reSelect: 'Re-select',
+ missingRequiredMetaFields: {
+ 0: 'Missing required meta field: %{fields}.',
+ 1: 'Missing required meta fields: %{fields}.',
+ },
+ },
+}
diff --git a/packages/@uppy/drag-drop/src/index.js b/packages/@uppy/drag-drop/src/index.js
index 835ce16708..e50e009ad0 100644
--- a/packages/@uppy/drag-drop/src/index.js
+++ b/packages/@uppy/drag-drop/src/index.js
@@ -4,6 +4,8 @@ const isDragDropSupported = require('@uppy/utils/lib/isDragDropSupported')
const getDroppedFiles = require('@uppy/utils/lib/getDroppedFiles')
const { h } = require('preact')
+const locale = require('./locale.js')
+
/**
* Drag & Drop plugin
*
@@ -18,12 +20,7 @@ module.exports = class DragDrop extends UIPlugin {
this.id = this.opts.id || 'DragDrop'
this.title = 'Drag & Drop'
- this.defaultLocale = {
- strings: {
- dropHereOr: 'Drop files here or %{browse}',
- browse: 'browse',
- },
- }
+ this.defaultLocale = locale
// Default options
const defaultOpts = {
diff --git a/packages/@uppy/drag-drop/src/locale.js b/packages/@uppy/drag-drop/src/locale.js
new file mode 100644
index 0000000000..d5c0446d93
--- /dev/null
+++ b/packages/@uppy/drag-drop/src/locale.js
@@ -0,0 +1,9 @@
+module.exports = {
+ strings: {
+ // Text to show on the droppable area.
+ // `%{browse}` is replaced with a link that opens the system file selection dialog.
+ dropHereOr: 'Drop here or %{browse}',
+ // Used as the label for the link that opens the system file selection dialog.
+ browse: 'browse',
+ },
+}
diff --git a/packages/@uppy/dropbox/src/index.js b/packages/@uppy/dropbox/src/index.js
index ed0b9dd8eb..a10187b7a6 100644
--- a/packages/@uppy/dropbox/src/index.js
+++ b/packages/@uppy/dropbox/src/index.js
@@ -3,6 +3,8 @@ const { Provider } = require('@uppy/companion-client')
const { ProviderViews } = require('@uppy/provider-views')
const { h } = require('preact')
+const locale = require('./locale')
+
module.exports = class Dropbox extends UIPlugin {
static VERSION = require('../package.json').version
@@ -29,11 +31,8 @@ module.exports = class Dropbox extends UIPlugin {
pluginId: this.id,
})
- this.defaultLocale = {
- strings: {
- pluginNameDropbox: 'Dropbox',
- },
- }
+ this.defaultLocale = locale
+
this.i18nInit()
this.title = this.i18n('pluginNameDropbox')
diff --git a/packages/@uppy/dropbox/src/locale.js b/packages/@uppy/dropbox/src/locale.js
new file mode 100644
index 0000000000..2c86a87245
--- /dev/null
+++ b/packages/@uppy/dropbox/src/locale.js
@@ -0,0 +1,5 @@
+module.exports = {
+ strings: {
+ pluginNameDropbox: 'Dropbox',
+ },
+}
diff --git a/packages/@uppy/facebook/src/index.js b/packages/@uppy/facebook/src/index.js
index 40e11be4da..fe1390ac12 100644
--- a/packages/@uppy/facebook/src/index.js
+++ b/packages/@uppy/facebook/src/index.js
@@ -3,6 +3,8 @@ const { Provider } = require('@uppy/companion-client')
const { ProviderViews } = require('@uppy/provider-views')
const { h } = require('preact')
+const locale = require('./locale.js')
+
module.exports = class Facebook extends UIPlugin {
static VERSION = require('../package.json').version
@@ -29,11 +31,8 @@ module.exports = class Facebook extends UIPlugin {
pluginId: this.id,
})
- this.defaultLocale = {
- strings: {
- pluginNameFacebook: 'Facebook',
- },
- }
+ this.defaultLocale = locale
+
this.i18nInit()
this.title = this.i18n('pluginNameFacebook')
diff --git a/packages/@uppy/facebook/src/locale.js b/packages/@uppy/facebook/src/locale.js
new file mode 100644
index 0000000000..b9530c2973
--- /dev/null
+++ b/packages/@uppy/facebook/src/locale.js
@@ -0,0 +1,5 @@
+module.exports = {
+ strings: {
+ pluginNameFacebook: 'Facebook',
+ },
+}
diff --git a/packages/@uppy/file-input/src/index.js b/packages/@uppy/file-input/src/index.js
index b0b49c2929..4e733ac424 100644
--- a/packages/@uppy/file-input/src/index.js
+++ b/packages/@uppy/file-input/src/index.js
@@ -2,6 +2,8 @@ const { UIPlugin } = require('@uppy/core')
const toArray = require('@uppy/utils/lib/toArray')
const { h } = require('preact')
+const locale = require('./locale')
+
module.exports = class FileInput extends UIPlugin {
static VERSION = require('../package.json').version
@@ -11,14 +13,7 @@ module.exports = class FileInput extends UIPlugin {
this.title = 'File Input'
this.type = 'acquirer'
- this.defaultLocale = {
- strings: {
- // The same key is used for the same purpose by @uppy/robodog's `form()` API, but our
- // locale pack scripts can't access it in Robodog. If it is updated here, it should
- // also be updated there!
- chooseFiles: 'Choose files',
- },
- }
+ this.defaultLocale = locale
// Default options
const defaultOptions = {
diff --git a/packages/@uppy/file-input/src/locale.js b/packages/@uppy/file-input/src/locale.js
new file mode 100644
index 0000000000..9c0fef83b4
--- /dev/null
+++ b/packages/@uppy/file-input/src/locale.js
@@ -0,0 +1,8 @@
+module.exports = {
+ strings: {
+ // The same key is used for the same purpose by @uppy/robodog's `form()` API, but our
+ // locale pack scripts can't access it in Robodog. If it is updated here, it should
+ // also be updated there!
+ chooseFiles: 'Choose files',
+ },
+}
diff --git a/packages/@uppy/google-drive/src/index.js b/packages/@uppy/google-drive/src/index.js
index 849ae1c374..2ffbf2f67c 100644
--- a/packages/@uppy/google-drive/src/index.js
+++ b/packages/@uppy/google-drive/src/index.js
@@ -3,6 +3,8 @@ const { Provider } = require('@uppy/companion-client')
const { h } = require('preact')
const DriveProviderViews = require('./DriveProviderViews')
+const locale = require('./locale')
+
module.exports = class GoogleDrive extends UIPlugin {
static VERSION = require('../package.json').version
@@ -45,11 +47,8 @@ module.exports = class GoogleDrive extends UIPlugin {
pluginId: this.id,
})
- this.defaultLocale = {
- strings: {
- pluginNameGoogleDrive: 'Google Drive',
- },
- }
+ this.defaultLocale = locale
+
this.i18nInit()
this.title = this.i18n('pluginNameGoogleDrive')
diff --git a/packages/@uppy/google-drive/src/locale.js b/packages/@uppy/google-drive/src/locale.js
new file mode 100644
index 0000000000..e4c06d82a8
--- /dev/null
+++ b/packages/@uppy/google-drive/src/locale.js
@@ -0,0 +1,5 @@
+module.exports = {
+ strings: {
+ pluginNameGoogleDrive: 'Google Drive',
+ },
+}
diff --git a/packages/@uppy/image-editor/src/index.js b/packages/@uppy/image-editor/src/index.js
index c94eee605c..e2abf74f23 100644
--- a/packages/@uppy/image-editor/src/index.js
+++ b/packages/@uppy/image-editor/src/index.js
@@ -2,6 +2,8 @@ const { UIPlugin } = require('@uppy/core')
const { h } = require('preact')
const Editor = require('./Editor')
+const locale = require('./locale.js')
+
module.exports = class ImageEditor extends UIPlugin {
// eslint-disable-next-line global-require
static VERSION = require('../package.json').version
@@ -12,18 +14,7 @@ module.exports = class ImageEditor extends UIPlugin {
this.title = 'Image Editor'
this.type = 'editor'
- this.defaultLocale = {
- strings: {
- revert: 'Revert',
- rotate: 'Rotate',
- zoomIn: 'Zoom in',
- zoomOut: 'Zoom out',
- flipHorizontal: 'Flip horizontal',
- aspectRatioSquare: 'Crop square',
- aspectRatioLandscape: 'Crop landscape (16:9)',
- aspectRatioPortrait: 'Crop portrait (9:16)',
- },
- }
+ this.defaultLocale = locale
const defaultCropperOptions = {
viewMode: 1,
diff --git a/packages/@uppy/image-editor/src/locale.js b/packages/@uppy/image-editor/src/locale.js
new file mode 100644
index 0000000000..119986f274
--- /dev/null
+++ b/packages/@uppy/image-editor/src/locale.js
@@ -0,0 +1,12 @@
+module.exports = {
+ strings: {
+ revert: 'Revert',
+ rotate: 'Rotate',
+ zoomIn: 'Zoom in',
+ zoomOut: 'Zoom out',
+ flipHorizontal: 'Flip horizontal',
+ aspectRatioSquare: 'Crop square',
+ aspectRatioLandscape: 'Crop landscape (16:9)',
+ aspectRatioPortrait: 'Crop portrait (9:16)',
+ },
+}
diff --git a/packages/@uppy/instagram/src/index.js b/packages/@uppy/instagram/src/index.js
index 4e53734f21..29c14bba86 100644
--- a/packages/@uppy/instagram/src/index.js
+++ b/packages/@uppy/instagram/src/index.js
@@ -3,6 +3,8 @@ const { Provider } = require('@uppy/companion-client')
const { ProviderViews } = require('@uppy/provider-views')
const { h } = require('preact')
+const locale = require('./locale.js')
+
module.exports = class Instagram extends UIPlugin {
static VERSION = require('../package.json').version
@@ -19,11 +21,8 @@ module.exports = class Instagram extends UIPlugin {
)
- this.defaultLocale = {
- strings: {
- pluginNameInstagram: 'Instagram',
- },
- }
+ this.defaultLocale = locale
+
this.i18nInit()
this.title = this.i18n('pluginNameInstagram')
diff --git a/packages/@uppy/instagram/src/locale.js b/packages/@uppy/instagram/src/locale.js
new file mode 100644
index 0000000000..b479118989
--- /dev/null
+++ b/packages/@uppy/instagram/src/locale.js
@@ -0,0 +1,5 @@
+module.exports = {
+ strings: {
+ pluginNameInstagram: 'Instagram',
+ },
+}
diff --git a/packages/@uppy/locales/src/en_US.js b/packages/@uppy/locales/src/en_US.js
index eaf70c2548..751b6b276a 100644
--- a/packages/@uppy/locales/src/en_US.js
+++ b/packages/@uppy/locales/src/en_US.js
@@ -32,15 +32,15 @@ en_US.strings = {
connectedToInternet: 'Connected to the Internet',
copyLink: 'Copy link',
copyLinkToClipboardFallback: 'Copy the URL below',
- copyLinkToClipboardSuccess: 'Link copied to clipboard',
+ copyLinkToClipboardSuccess: 'Link copied to clipboard.',
creatingAssembly: 'Preparing upload...',
creatingAssemblyFailed: 'Transloadit: Could not create Assembly',
- dashboardTitle: 'File Uploader',
- dashboardWindowTitle: 'File Uploader Window (Press escape to close)',
+ dashboardTitle: 'Uppy Dashboard',
+ dashboardWindowTitle: 'Uppy Dashboard Window (Press escape to close)',
dataUploadedOfTotal: '%{complete} of %{total}',
discardRecordedFile: 'Discard recorded file',
done: 'Done',
- dropHereOr: 'Drop files here or %{browse}',
+ dropHereOr: 'Drop here or %{browse}',
dropHint: 'Drop your files here',
dropPasteBoth: 'Drop files here, %{browseFiles} or %{browseFolders}',
dropPasteFiles: 'Drop files here or %{browseFiles}',
@@ -117,7 +117,7 @@ en_US.strings = {
'0': 'We could not fully recover 1 file. Please re-select it and resume the upload.',
'1': 'We could not fully recover %{smart_count} files. Please re-select them and resume the upload.',
},
- removeFile: 'Remove file %{file}',
+ removeFile: 'Remove file',
reSelect: 'Re-select',
resetFilter: 'Reset filter',
resume: 'Resume',
diff --git a/packages/@uppy/onedrive/src/index.js b/packages/@uppy/onedrive/src/index.js
index b7f4f4152c..2284abb0c0 100644
--- a/packages/@uppy/onedrive/src/index.js
+++ b/packages/@uppy/onedrive/src/index.js
@@ -3,6 +3,8 @@ const { Provider } = require('@uppy/companion-client')
const { ProviderViews } = require('@uppy/provider-views')
const { h } = require('preact')
+const locale = require('./locale')
+
module.exports = class OneDrive extends UIPlugin {
static VERSION = require('../package.json').version
@@ -31,11 +33,8 @@ module.exports = class OneDrive extends UIPlugin {
pluginId: this.id,
})
- this.defaultLocale = {
- strings: {
- pluginNameOneDrive: 'OneDrive',
- },
- }
+ this.defaultLocale = locale
+
this.i18nInit()
this.title = this.i18n('pluginNameOneDrive')
diff --git a/packages/@uppy/onedrive/src/locale.js b/packages/@uppy/onedrive/src/locale.js
new file mode 100644
index 0000000000..7b0cc7e8f7
--- /dev/null
+++ b/packages/@uppy/onedrive/src/locale.js
@@ -0,0 +1,5 @@
+module.exports = {
+ strings: {
+ pluginNameOneDrive: 'OneDrive',
+ },
+}
diff --git a/packages/@uppy/screen-capture/src/index.js b/packages/@uppy/screen-capture/src/index.js
index e99ba5e332..1eb5c92c06 100644
--- a/packages/@uppy/screen-capture/src/index.js
+++ b/packages/@uppy/screen-capture/src/index.js
@@ -4,6 +4,8 @@ const getFileTypeExtension = require('@uppy/utils/lib/getFileTypeExtension')
const ScreenRecIcon = require('./ScreenRecIcon')
const CaptureScreen = require('./CaptureScreen')
+const locale = require('./locale')
+
// Adapted from: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
function getMediaDevices () {
// check if screen capturing is supported
@@ -26,17 +28,7 @@ module.exports = class ScreenCapture extends UIPlugin {
this.type = 'acquirer'
this.icon = ScreenRecIcon
- this.defaultLocale = {
- strings: {
- startCapturing: 'Begin screen capturing',
- stopCapturing: 'Stop screen capturing',
- submitRecordedFile: 'Submit recorded file',
- streamActive: 'Stream active',
- streamPassive: 'Stream passive',
- micDisabled: 'Microphone access denied by user',
- recording: 'Recording',
- },
- }
+ this.defaultLocale = locale
// set default options
// https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints
diff --git a/packages/@uppy/screen-capture/src/locale.js b/packages/@uppy/screen-capture/src/locale.js
new file mode 100644
index 0000000000..199ed5c6c7
--- /dev/null
+++ b/packages/@uppy/screen-capture/src/locale.js
@@ -0,0 +1,11 @@
+module.exports = {
+ strings: {
+ startCapturing: 'Begin screen capturing',
+ stopCapturing: 'Stop screen capturing',
+ submitRecordedFile: 'Submit recorded file',
+ streamActive: 'Stream active',
+ streamPassive: 'Stream passive',
+ micDisabled: 'Microphone access denied by user',
+ recording: 'Recording',
+ },
+}
diff --git a/packages/@uppy/status-bar/src/index.js b/packages/@uppy/status-bar/src/index.js
index a15910f9f5..b714657beb 100644
--- a/packages/@uppy/status-bar/src/index.js
+++ b/packages/@uppy/status-bar/src/index.js
@@ -5,6 +5,8 @@ const getTextDirection = require('@uppy/utils/lib/getTextDirection')
const statusBarStates = require('./StatusBarStates')
const StatusBarUI = require('./StatusBar')
+const locale = require('./locale.js')
+
/**
* StatusBar: renders a status bar with upload/pause/resume/cancel/retry buttons,
* progress percentage and time remaining.
@@ -19,39 +21,7 @@ module.exports = class StatusBar extends UIPlugin {
this.title = 'StatusBar'
this.type = 'progressindicator'
- this.defaultLocale = {
- strings: {
- uploading: 'Uploading',
- upload: 'Upload',
- complete: 'Complete',
- uploadFailed: 'Upload failed',
- paused: 'Paused',
- retry: 'Retry',
- retryUpload: 'Retry upload',
- cancel: 'Cancel',
- pause: 'Pause',
- resume: 'Resume',
- done: 'Done',
- filesUploadedOfTotal: {
- 0: '%{complete} of %{smart_count} file uploaded',
- 1: '%{complete} of %{smart_count} files uploaded',
- },
- dataUploadedOfTotal: '%{complete} of %{total}',
- xTimeLeft: '%{time} left',
- uploadXFiles: {
- 0: 'Upload %{smart_count} file',
- 1: 'Upload %{smart_count} files',
- },
- uploadXNewFiles: {
- 0: 'Upload +%{smart_count} file',
- 1: 'Upload +%{smart_count} files',
- },
- xMoreFilesAdded: {
- 0: '%{smart_count} more file added',
- 1: '%{smart_count} more files added',
- },
- },
- }
+ this.defaultLocale = locale
// set default options
const defaultOptions = {
diff --git a/packages/@uppy/status-bar/src/locale.js b/packages/@uppy/status-bar/src/locale.js
new file mode 100644
index 0000000000..7da3099a3c
--- /dev/null
+++ b/packages/@uppy/status-bar/src/locale.js
@@ -0,0 +1,48 @@
+module.exports = {
+ strings: {
+ // Shown in the status bar while files are being uploaded.
+ uploading: 'Uploading',
+ // Shown in the status bar once all files have been uploaded.
+ complete: 'Complete',
+ // Shown in the status bar if an upload failed.
+ uploadFailed: 'Upload failed',
+ // Shown in the status bar while the upload is paused.
+ paused: 'Paused',
+ // Used as the label for the button that retries an upload.
+ retry: 'Retry',
+ // Used as the label for the button that cancels an upload.
+ cancel: 'Cancel',
+ // Used as the label for the button that pauses an upload.
+ pause: 'Pause',
+ // Used as the label for the button that resumes an upload.
+ resume: 'Resume',
+ // Used as the label for the button that resets the upload state after an upload
+ done: 'Done',
+ // When `showProgressDetails` is set, shows the number of files that have been fully uploaded so far.
+ filesUploadedOfTotal: {
+ 0: '%{complete} of %{smart_count} file uploaded',
+ 1: '%{complete} of %{smart_count} files uploaded',
+ },
+ // When `showProgressDetails` is set, shows the amount of bytes that have been uploaded so far.
+ dataUploadedOfTotal: '%{complete} of %{total}',
+ // When `showProgressDetails` is set, shows an estimation of how long the upload will take to complete.
+ xTimeLeft: '%{time} left',
+ // Used as the label for the button that starts an upload.
+ uploadXFiles: {
+ 0: 'Upload %{smart_count} file',
+ 1: 'Upload %{smart_count} files',
+ },
+ // Used as the label for the button that starts an upload, if another upload has been started in the past
+ // and new files were added later.
+ uploadXNewFiles: {
+ 0: 'Upload +%{smart_count} file',
+ 1: 'Upload +%{smart_count} files',
+ },
+ upload: 'Upload',
+ retryUpload: 'Retry upload',
+ xMoreFilesAdded: {
+ 0: '%{smart_count} more file added',
+ 1: '%{smart_count} more files added',
+ },
+ },
+}
diff --git a/packages/@uppy/thumbnail-generator/src/index.js b/packages/@uppy/thumbnail-generator/src/index.js
index a9d532fe5c..0afb5fda8b 100644
--- a/packages/@uppy/thumbnail-generator/src/index.js
+++ b/packages/@uppy/thumbnail-generator/src/index.js
@@ -4,6 +4,8 @@ const isObjectURL = require('@uppy/utils/lib/isObjectURL')
const isPreviewSupported = require('@uppy/utils/lib/isPreviewSupported')
const exifr = require('exifr/dist/mini.legacy.umd.js')
+const locale = require('./locale')
+
/**
* The Thumbnail Generator plugin
*/
@@ -21,11 +23,7 @@ module.exports = class ThumbnailGenerator extends UIPlugin {
this.defaultThumbnailDimension = 200
this.thumbnailType = this.opts.thumbnailType || 'image/jpeg'
- this.defaultLocale = {
- strings: {
- generatingThumbnails: 'Generating thumbnails...',
- },
- }
+ this.defaultLocale = locale
const defaultOptions = {
thumbnailWidth: null,
diff --git a/packages/@uppy/thumbnail-generator/src/locale.js b/packages/@uppy/thumbnail-generator/src/locale.js
new file mode 100644
index 0000000000..df1d0f4487
--- /dev/null
+++ b/packages/@uppy/thumbnail-generator/src/locale.js
@@ -0,0 +1,5 @@
+module.exports = {
+ strings: {
+ generatingThumbnails: 'Generating thumbnails...',
+ },
+}
diff --git a/packages/@uppy/transloadit/src/index.js b/packages/@uppy/transloadit/src/index.js
index 81b1d58677..135f1caece 100644
--- a/packages/@uppy/transloadit/src/index.js
+++ b/packages/@uppy/transloadit/src/index.js
@@ -6,6 +6,8 @@ const Client = require('./Client')
const AssemblyOptions = require('./AssemblyOptions')
const AssemblyWatcher = require('./AssemblyWatcher')
+const locale = require('./locale')
+
function defaultGetAssemblyOptions (file, options) {
return {
params: options.params,
@@ -38,13 +40,7 @@ module.exports = class Transloadit extends BasePlugin {
this.id = this.opts.id || 'Transloadit'
this.title = 'Transloadit'
- this.defaultLocale = {
- strings: {
- creatingAssembly: 'Preparing upload...',
- creatingAssemblyFailed: 'Transloadit: Could not create Assembly',
- encoding: 'Encoding...',
- },
- }
+ this.defaultLocale = locale
const defaultOptions = {
service: 'https://api2.transloadit.com',
diff --git a/packages/@uppy/transloadit/src/locale.js b/packages/@uppy/transloadit/src/locale.js
new file mode 100644
index 0000000000..9173884a47
--- /dev/null
+++ b/packages/@uppy/transloadit/src/locale.js
@@ -0,0 +1,11 @@
+module.exports = {
+ strings: {
+ // Shown while Assemblies are being created for an upload.
+ creatingAssembly: 'Preparing upload...',
+ // Shown if an Assembly could not be created.
+ creatingAssemblyFailed: 'Transloadit: Could not create Assembly',
+ // Shown after uploads have succeeded, but when the Assembly is still executing.
+ // This only shows if `waitForMetadata` or `waitForEncoding` was enabled.
+ encoding: 'Encoding...',
+ },
+}
diff --git a/packages/@uppy/url/src/index.js b/packages/@uppy/url/src/index.js
index 0b0b5ce154..2213277ec1 100644
--- a/packages/@uppy/url/src/index.js
+++ b/packages/@uppy/url/src/index.js
@@ -5,6 +5,8 @@ const UrlUI = require('./UrlUI.js')
const toArray = require('@uppy/utils/lib/toArray')
const forEachDroppedOrPastedUrl = require('./utils/forEachDroppedOrPastedUrl')
+const locale = require('./locale')
+
function UrlIcon () {
return (
)
- this.defaultLocale = {
- strings: {
- pluginNameCamera: 'Camera',
- smile: 'Smile!',
- takePicture: 'Take a picture',
- startRecording: 'Begin video recording',
- stopRecording: 'Stop video recording',
- allowAccessTitle: 'Please allow access to your camera',
- allowAccessDescription: 'In order to take pictures or record video with your camera, please allow camera access for this site.',
- noCameraTitle: 'Camera Not Available',
- noCameraDescription: 'In order to take pictures or record video, please connect a camera device',
- recordingStoppedMaxSize: 'Recording stopped because the file size is about to exceed the limit',
- recordingLength: 'Recording length %{recording_length}',
- submitRecordedFile: 'Submit recorded file',
- discardRecordedFile: 'Discard recorded file',
- },
- }
+ this.defaultLocale = locale
// set default options
const defaultOptions = {
diff --git a/packages/@uppy/webcam/src/locale.js b/packages/@uppy/webcam/src/locale.js
new file mode 100644
index 0000000000..35b45817e0
--- /dev/null
+++ b/packages/@uppy/webcam/src/locale.js
@@ -0,0 +1,28 @@
+module.exports = {
+ strings: {
+ pluginNameCamera: 'Camera',
+ noCameraTitle: 'Camera Not Available',
+ noCameraDescription: 'In order to take pictures or record video, please connect a camera device',
+ recordingStoppedMaxSize: 'Recording stopped because the file size is about to exceed the limit',
+ submitRecordedFile: 'Submit recorded file',
+ discardRecordedFile: 'Discard recorded file',
+ // Shown before a picture is taken when the `countdown` option is set.
+ smile: 'Smile!',
+ // Used as the label for the button that takes a picture.
+ // This is not visibly rendered but is picked up by screen readers.
+ takePicture: 'Take a picture',
+ // Used as the label for the button that starts a video recording.
+ // This is not visibly rendered but is picked up by screen readers.
+ startRecording: 'Begin video recording',
+ // Used as the label for the button that stops a video recording.
+ // This is not visibly rendered but is picked up by screen readers.
+ stopRecording: 'Stop video recording',
+ // Used as the label for the recording length counter. See the showRecordingLength option.
+ // This is not visibly rendered but is picked up by screen readers.
+ recordingLength: 'Recording length %{recording_length}',
+ // Title on the “allow access” screen
+ allowAccessTitle: 'Please allow access to your camera',
+ // Description on the “allow access” screen
+ allowAccessDescription: 'In order to take pictures or record video with your camera, please allow camera access for this site.',
+ },
+}
diff --git a/packages/@uppy/xhr-upload/src/index.js b/packages/@uppy/xhr-upload/src/index.js
index 2782a549b5..f3e2c6d90e 100644
--- a/packages/@uppy/xhr-upload/src/index.js
+++ b/packages/@uppy/xhr-upload/src/index.js
@@ -10,6 +10,8 @@ const { RateLimitedQueue, internalRateLimitedQueue } = require('@uppy/utils/lib/
const NetworkError = require('@uppy/utils/lib/NetworkError')
const isNetworkError = require('@uppy/utils/lib/isNetworkError')
+const locale = require('./locale')
+
function buildResponseError (xhr, err) {
let error = err
// No error message
@@ -53,11 +55,7 @@ module.exports = class XHRUpload extends BasePlugin {
this.id = this.opts.id || 'XHRUpload'
this.title = 'XHRUpload'
- this.defaultLocale = {
- strings: {
- timedOut: 'Upload stalled for %{seconds} seconds, aborting.',
- },
- }
+ this.defaultLocale = locale
// Default options
const defaultOptions = {
diff --git a/packages/@uppy/xhr-upload/src/locale.js b/packages/@uppy/xhr-upload/src/locale.js
new file mode 100644
index 0000000000..24f6aa38fc
--- /dev/null
+++ b/packages/@uppy/xhr-upload/src/locale.js
@@ -0,0 +1,6 @@
+module.exports = {
+ strings: {
+ // Shown in the Informer if an upload is being canceled because it stalled for too long.
+ timedOut: 'Upload stalled for %{seconds} seconds, aborting.',
+ },
+}
diff --git a/packages/@uppy/zoom/src/index.js b/packages/@uppy/zoom/src/index.js
index 542f5a7587..e02a964ee8 100644
--- a/packages/@uppy/zoom/src/index.js
+++ b/packages/@uppy/zoom/src/index.js
@@ -3,6 +3,8 @@ const { Provider } = require('@uppy/companion-client')
const { ProviderViews } = require('@uppy/provider-views')
const { h } = require('preact')
+const locale = require('./locale')
+
module.exports = class Zoom extends UIPlugin {
static VERSION = require('../package.json').version
@@ -30,11 +32,8 @@ module.exports = class Zoom extends UIPlugin {
pluginId: this.id,
})
- this.defaultLocale = {
- strings: {
- pluginNameZoom: 'Zoom',
- },
- }
+ this.defaultLocale = locale
+
this.i18nInit()
this.title = this.i18n('pluginNameZoom')
diff --git a/packages/@uppy/zoom/src/locale.js b/packages/@uppy/zoom/src/locale.js
new file mode 100644
index 0000000000..9f090a3d5b
--- /dev/null
+++ b/packages/@uppy/zoom/src/locale.js
@@ -0,0 +1,5 @@
+module.exports = {
+ strings: {
+ pluginNameZoom: 'Zoom',
+ },
+}
diff --git a/private/locale-pack/helpers.mjs b/private/locale-pack/helpers.mjs
new file mode 100644
index 0000000000..a0269ff277
--- /dev/null
+++ b/private/locale-pack/helpers.mjs
@@ -0,0 +1,22 @@
+import glob from 'glob'
+
+export function getPaths (globPath) {
+ return new Promise((resolve, reject) => {
+ glob(globPath, (error, paths) => {
+ if (error) reject(error)
+ else resolve(paths)
+ })
+ })
+}
+
+export function sortObjectAlphabetically (obj) {
+ return Object.fromEntries(
+ Object.entries(obj).sort(([keyA], [keyB]) => keyA.localeCompare(keyB))
+ )
+}
+
+export function omit (object, key) {
+ const copy = { ...object }
+ delete copy[key]
+ return copy
+}
diff --git a/private/locale-pack/index.mjs b/private/locale-pack/index.mjs
new file mode 100644
index 0000000000..a98166d860
--- /dev/null
+++ b/private/locale-pack/index.mjs
@@ -0,0 +1,168 @@
+/* eslint-disable no-console, prefer-arrow-callback */
+import path from 'node:path'
+import fs from 'node:fs'
+import { readFile, writeFile } from 'node:fs/promises'
+import { fileURLToPath } from 'node:url'
+
+import dedent from 'dedent'
+import stringifyObject from 'stringify-object'
+import { remark } from 'remark'
+import { headingRange } from 'mdast-util-heading-range'
+import remarkFrontmatter from 'remark-frontmatter'
+
+import remarkConfig from '../remark-lint-uppy/index.js'
+
+import { getPaths, sortObjectAlphabetically } from './helpers.mjs'
+
+const { settings: remarkSettings } = remarkConfig
+
+const root = fileURLToPath(new URL('../../', import.meta.url))
+
+const localesPath = path.join(root, 'packages', '@uppy', 'locales')
+const templatePath = path.join(localesPath, 'template.js')
+const englishLocalePath = path.join(localesPath, 'src', 'en_US.js')
+
+main()
+ .then(() => {
+ console.log(`✅ Generated '${englishLocalePath}'`)
+ console.log('✅ Generated locale docs')
+ console.log('✅ Generated types')
+ })
+ .catch((error) => {
+ console.error(error)
+ process.exit(1)
+ })
+
+function main () {
+ return getPaths(`${root}/packages/@uppy/**/src/locale.js`)
+ .then(importFiles)
+ .then(createCombinedLocale)
+ .then(({ combinedLocale, locales }) => ({
+ combinedLocale: sortObjectAlphabetically(combinedLocale),
+ locales,
+ }))
+ .then(({ combinedLocale, locales }) => {
+ return readFile(templatePath, 'utf-8')
+ .then((fileString) => populateTemplate(fileString, combinedLocale))
+ .then((file) => writeFile(englishLocalePath, file))
+ .then(() => {
+ for (const [pluginName, locale] of Object.entries(locales)) {
+ generateLocaleDocs(pluginName)
+ generateTypes(pluginName, locale)
+ }
+ return locales
+ })
+ })
+}
+
+async function importFiles (paths) {
+ const locales = {}
+
+ for (const filePath of paths) {
+ const pluginName = path.basename(path.join(filePath, '..', '..'))
+ // Note: `.default` should be removed when we move to ESM
+ const locale = (await import(filePath)).default
+
+ locales[pluginName] = locale
+ }
+
+ return locales
+}
+
+function createCombinedLocale (locales) {
+ return new Promise((resolve, reject) => {
+ const combinedLocale = {}
+ const entries = Object.entries(locales)
+
+ for (const [pluginName, locale] of entries) {
+ Object.entries(locale.strings).forEach(([key, value]) => {
+ if (key in combinedLocale && value !== combinedLocale[key]) {
+ reject(new Error(`'${key}' from ${pluginName} already exists in locale pack.`))
+ }
+ combinedLocale[key] = value
+ })
+ }
+
+ resolve({ combinedLocale, locales })
+ })
+}
+
+function populateTemplate (fileString, combinedLocale) {
+ const formattedLocale = stringifyObject(combinedLocale, {
+ indent: ' ',
+ singleQuotes: true,
+ inlineCharacterLimit: 12,
+ })
+ return fileString.replace('en_US.strings = {}', `en_US.strings = ${formattedLocale}`)
+}
+
+function generateTypes (pluginName, locale) {
+ const allowedStringTypes = Object.keys(locale.strings)
+ .map((key) => ` | '${key}'`)
+ .join('\n')
+ const pluginClassName = pluginName
+ .split('-')
+ .map((str) => str.replace(/^\w/, (c) => c.toUpperCase()))
+ .join('')
+
+ const localePath = path.join(
+ root,
+ 'packages',
+ '@uppy',
+ pluginName,
+ 'types',
+ 'generatedLocale.d.ts'
+ )
+
+ const localeTypes = dedent`
+ /* eslint-disable */
+ import type { Locale } from '@uppy/core'
+
+ type ${pluginClassName}Locale = Locale<
+ ${allowedStringTypes}
+ >
+
+ export default ${pluginClassName}Locale
+ `
+
+ fs.writeFileSync(localePath, localeTypes)
+}
+
+function generateLocaleDocs (pluginName) {
+ const fileName = `${pluginName}.md`
+ const docPath = path.join(root, 'website', 'src', 'docs', fileName)
+ const localePath = path.join(root, 'packages', '@uppy', pluginName, 'src', 'locale.js')
+ const rangeOptions = { test: 'locale: {}', ignoreFinalDefinitions: true }
+
+ if (!fs.existsSync(docPath)) {
+ console.error(
+ `⚠️ Could not find markdown documentation file for "${pluginName}". Make sure the plugin name matches the markdown file name.`
+ )
+ return
+ }
+
+ remark()
+ .data('settings', remarkSettings)
+ .use(remarkFrontmatter)
+ .use(() => (tree) => {
+ // Replace all nodes after the locale heading until the next heading (or eof)
+ headingRange(tree, rangeOptions, (start, _, end) => [
+ start,
+ {
+ type: 'html',
+ // `module.exports` is not allowed by eslint in our docs.
+ // The script outputs an extra newline which also isn't excepted by eslint
+ value: '',
+ },
+ {
+ type: 'code',
+ lang: 'js',
+ meta: null,
+ value: fs.readFileSync(localePath, 'utf-8'),
+ },
+ end,
+ ])
+ })
+ .process(fs.readFileSync(docPath))
+ .then((file) => fs.writeFileSync(docPath, String(file)))
+}
diff --git a/private/locale-pack/package.json b/private/locale-pack/package.json
new file mode 100644
index 0000000000..cef3d6905c
--- /dev/null
+++ b/private/locale-pack/package.json
@@ -0,0 +1,20 @@
+{
+ "private": true,
+ "name": "locale-pack",
+ "author": "Merlijn Vos ",
+ "description": "Generate locale pack, types, and documentation",
+ "main": "index.mjs",
+ "scripts": {
+ "build": "yarn node index.mjs",
+ "test": "yarn node test.mjs"
+ },
+ "dependencies": {
+ "chalk": "^4.1.2",
+ "dedent": "^0.7.0",
+ "glob": "^7.2.0",
+ "mdast-util-heading-range": "^3.1.0",
+ "remark": "^14.0.1",
+ "remark-frontmatter": "^4.0.1",
+ "stringify-object": "^4.0.0"
+ }
+}
diff --git a/private/locale-pack/test.mjs b/private/locale-pack/test.mjs
new file mode 100644
index 0000000000..2e8a19b32f
--- /dev/null
+++ b/private/locale-pack/test.mjs
@@ -0,0 +1,159 @@
+/* eslint-disable no-console, prefer-arrow-callback */
+import path from 'node:path'
+import fs from 'node:fs'
+import { fileURLToPath } from 'node:url'
+
+import glob from 'glob'
+import chalk from 'chalk'
+
+import { getPaths, omit } from './helpers.mjs'
+
+const root = fileURLToPath(new URL('../../', import.meta.url))
+const leadingLocaleName = 'en_US'
+const mode = process.argv[2]
+const pluginLocaleDependencies = {
+ core: 'provider-views',
+}
+
+test()
+ .then(() => {
+ console.log('\n')
+ console.log('No blocking issues found')
+ })
+ .catch((error) => {
+ console.error(error)
+ process.exit(1)
+ })
+
+function test () {
+ switch (mode) {
+ case 'unused':
+ return getPaths(`${root}/packages/@uppy/**/src/locale.js`)
+ .then((paths) => paths.map((filePath) => path.basename(path.join(filePath, '..', '..'))))
+ .then(getAllFilesPerPlugin)
+ .then(unused)
+
+ case 'warnings':
+ return getPaths(`${root}/packages/@uppy/locales/src/*.js`)
+ .then(importFiles)
+ .then((locales) => ({
+ leadingLocale: locales[leadingLocaleName],
+ followerLocales: omit(locales, leadingLocaleName),
+ }))
+ .then(warnings)
+
+ default:
+ return Promise.reject(new Error(`Invalid mode "${mode}"`))
+ }
+}
+
+async function importFiles (paths) {
+ const locales = {}
+
+ for (const filePath of paths) {
+ const localeName = path.basename(filePath, '.js')
+ // Note: `.default` should be removed when we move to ESM
+ const locale = (await import(filePath)).default
+
+ locales[localeName] = locale.strings
+ }
+
+ return locales
+}
+
+function getAllFilesPerPlugin (pluginNames) {
+ const filesPerPlugin = {}
+
+ function getFiles (name) {
+ return glob
+ .sync(`${root}/packages/@uppy/${name}/lib/**/*.js`)
+ .filter((filePath) => !filePath.includes('locale.js'))
+ .map((filePath) => fs.readFileSync(filePath, 'utf-8'))
+ }
+
+ for (const name of pluginNames) {
+ filesPerPlugin[name] = getFiles(name)
+
+ if (name in pluginLocaleDependencies) {
+ filesPerPlugin[name] = filesPerPlugin[name].concat(
+ getFiles(pluginLocaleDependencies[name])
+ )
+ }
+ }
+
+ return filesPerPlugin
+}
+
+async function unused (filesPerPlugin, data) {
+ for (const [name, fileStrings] of Object.entries(filesPerPlugin)) {
+ const fileString = fileStrings.join('\n')
+ const localePath = path.join(
+ root,
+ 'packages',
+ '@uppy',
+ name,
+ 'src',
+ 'locale.js'
+ )
+ const locale = (await import(localePath)).default
+
+ for (const key of Object.keys(locale.strings)) {
+ const regPat = new RegExp(
+ `(i18n|i18nArray)\\([^\\)]*['\`"]${key}['\`"]`,
+ 'g'
+ )
+ if (!fileString.match(regPat)) {
+ return Promise.reject(new Error(`Unused locale key "${key}" in @uppy/${name}`))
+ }
+ }
+ }
+
+ return data
+}
+
+function warnings ({ leadingLocale, followerLocales }) {
+ const entries = Object.entries(followerLocales)
+ const logs = []
+
+ for (const [name, locale] of entries) {
+ const missing = Object.keys(leadingLocale).filter((key) => !(key in locale))
+ const excess = Object.keys(locale).filter((key) => !(key in leadingLocale))
+
+ logs.push('\n')
+ logs.push(`--> Keys from ${leadingLocaleName} missing in ${name}`)
+ logs.push('\n')
+
+ for (const key of missing) {
+ let value = leadingLocale[key]
+
+ if (typeof value === 'object') {
+ // For values with plural forms, just take the first one right now
+ value = value[Object.keys(value)[0]]
+ }
+
+ logs.push(
+ [
+ `${chalk.cyan(name)} locale has missing string: '${chalk.red(key)}'`,
+ `that is present in ${chalk.cyan(leadingLocaleName)}`,
+ `with value: ${chalk.yellow(value)}`,
+ ].join(' ')
+ )
+ }
+
+ logs.push('\n')
+ logs.push(`--> Keys from ${name} missing in ${leadingLocaleName}`)
+ logs.push('\n')
+
+ for (const key of excess) {
+ logs.push(
+ [
+ `${chalk.cyan(name)} locale has excess string:`,
+ `'${chalk.yellow(key)}' that is not present`,
+ `in ${chalk.cyan(leadingLocaleName)}.`,
+ ].join(' ')
+ )
+ }
+ }
+
+ console.log(logs.join('\n'))
+}
diff --git a/test/endtoend/create-react-app/package-lock.json b/test/endtoend/create-react-app/package-lock.json
index 4d62614926..f13f221103 100644
--- a/test/endtoend/create-react-app/package-lock.json
+++ b/test/endtoend/create-react-app/package-lock.json
@@ -19104,19 +19104,6 @@
"is-typedarray": "^1.0.0"
}
},
- "node_modules/typescript": {
- "version": "4.3.5",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
- "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
- "peer": true,
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=4.2.0"
- }
- },
"node_modules/unbox-primitive": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
@@ -24014,8 +24001,7 @@
"acorn-jsx": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "requires": {}
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="
},
"acorn-walk": {
"version": "7.2.0",
@@ -24079,14 +24065,12 @@
"ajv-errors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
- "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==",
- "requires": {}
+ "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ=="
},
"ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
- "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
- "requires": {}
+ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="
},
"alphanum-sort": {
"version": "1.0.2",
@@ -24547,8 +24531,7 @@
"babel-plugin-named-asset-import": {
"version": "0.3.7",
"resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.7.tgz",
- "integrity": "sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw==",
- "requires": {}
+ "integrity": "sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw=="
},
"babel-plugin-polyfill-corejs2": {
"version": "0.2.2",
@@ -27159,8 +27142,7 @@
"eslint-plugin-react-hooks": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz",
- "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==",
- "requires": {}
+ "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ=="
},
"eslint-plugin-testing-library": {
"version": "3.10.2",
@@ -29853,8 +29835,7 @@
"jest-pnp-resolver": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz",
- "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==",
- "requires": {}
+ "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w=="
},
"jest-regex-util": {
"version": "26.0.0",
@@ -35830,12 +35811,6 @@
"is-typedarray": "^1.0.0"
}
},
- "typescript": {
- "version": "4.3.5",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
- "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
- "peer": true
- },
"unbox-primitive": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
@@ -37524,8 +37499,7 @@
"ws": {
"version": "7.5.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz",
- "integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==",
- "requires": {}
+ "integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg=="
},
"xml-name-validator": {
"version": "3.0.0",
diff --git a/website/src/docs/aws-s3.md b/website/src/docs/aws-s3.md
index ee88a04e58..cfbef44c7c 100644
--- a/website/src/docs/aws-s3.md
+++ b/website/src/docs/aws-s3.md
@@ -115,17 +115,15 @@ This option is useful when uploading to an S3-like service that doesn’t reply
### `locale: {}`
-Localize text that is shown to the user.
-
-The default English strings are:
+
```js
-const locales = {
+module.exports = {
strings: {
- // Shown in the StatusBar while the upload is being signed.
- preparingUpload: 'Preparing upload...',
+ timedOut: 'Upload stalled for %{seconds} seconds, aborting.',
},
}
+
```
## S3 Bucket configuration
diff --git a/website/src/docs/box.md b/website/src/docs/box.md
index 4cc33f6025..18648e8cea 100644
--- a/website/src/docs/box.md
+++ b/website/src/docs/box.md
@@ -127,14 +127,13 @@ This option correlates to the [RequestCredentials value](https://developer.mozil
### `locale: {}`
-Localize text that is shown to the user.
-
-The default English strings are:
+
```js
-const locales = {
+module.exports = {
strings: {
- // TODO
+ pluginNameBox: 'Box',
},
}
+
```
diff --git a/website/src/docs/uppy.md b/website/src/docs/core.md
similarity index 92%
rename from website/src/docs/uppy.md
rename to website/src/docs/core.md
index c88e386c37..22e41be1fd 100644
--- a/website/src/docs/uppy.md
+++ b/website/src/docs/core.md
@@ -277,57 +277,70 @@ const uppy = new Uppy({
### `locale: {}`
-This allows you to override language strings:
+
```js
-const uppy = new Uppy({
- // ...
- locale: {
- strings: {
- youCanOnlyUploadX: {
- 0: 'You can only upload %{smart_count} file',
- 1: 'You can only upload %{smart_count} files',
- },
- youHaveToAtLeastSelectX: {
- 0: 'You have to select at least %{smart_count} file',
- 1: 'You have to select at least %{smart_count} files',
- },
- exceedsSize: 'This file exceeds maximum allowed size of %{size}',
- youCanOnlyUploadFileTypes: 'You can only upload: %{types}',
- companionError: 'Connection with Companion failed',
+module.exports = {
+ strings: {
+ addBulkFilesFailed: {
+ 0: 'Failed to add %{smart_count} file due to an internal error',
+ 1: 'Failed to add %{smart_count} files due to internal errors',
+ },
+ youCanOnlyUploadX: {
+ 0: 'You can only upload %{smart_count} file',
+ 1: 'You can only upload %{smart_count} files',
+ },
+ youHaveToAtLeastSelectX: {
+ 0: 'You have to select at least %{smart_count} file',
+ 1: 'You have to select at least %{smart_count} files',
+ },
+ exceedsSize: '%{file} exceeds maximum allowed size of %{size}',
+ missingRequiredMetaField: 'Missing required meta fields',
+ missingRequiredMetaFieldOnFile:
+ 'Missing required meta fields in %{fileName}',
+ inferiorSize: 'This file is smaller than the allowed size of %{size}',
+ youCanOnlyUploadFileTypes: 'You can only upload: %{types}',
+ noMoreFilesAllowed: 'Cannot add more files',
+ noDuplicates:
+ "Cannot add the duplicate file '%{fileName}', it already exists",
+ companionError: 'Connection with Companion failed',
+ authAborted: 'Authentication aborted',
+ companionUnauthorizeHint:
+ 'To unauthorize to your %{provider} account, please go to %{url}',
+ failedToUpload: 'Failed to upload %{file}',
+ noInternetConnection: 'No Internet connection',
+ connectedToInternet: 'Connected to the Internet',
+ // Strings for remote providers
+ noFilesFound: 'You have no files or folders here',
+ selectX: {
+ 0: 'Select %{smart_count}',
+ 1: 'Select %{smart_count}',
+ },
+ allFilesFromFolderNamed: 'All files from folder %{name}',
+ openFolderNamed: 'Open folder %{name}',
+ cancel: 'Cancel',
+ logOut: 'Log out',
+ filter: 'Filter',
+ resetFilter: 'Reset filter',
+ loading: 'Loading...',
+ authenticateWithTitle:
+ 'Please authenticate with %{pluginName} to select files',
+ authenticateWith: 'Connect to %{pluginName}',
+ signInWithGoogle: 'Sign in with Google',
+ searchImages: 'Search for images',
+ enterTextToSearch: 'Enter text to search for images',
+ backToSearch: 'Back to Search',
+ emptyFolderAdded: 'No files were added from empty folder',
+ folderAlreadyAdded: 'The folder "%{folder}" was already added',
+ folderAdded: {
+ 0: 'Added %{smart_count} file from %{folder}',
+ 1: 'Added %{smart_count} files from %{folder}',
},
},
-})
-```
-
-Instead of overriding strings yourself, consider using [one of our language packs](https://github.com/transloadit/uppy/tree/master/packages/%40uppy/locales) (or contributing one!):
-
-```js
-import russianLocale from '@uppy/locales/lib/ru_RU'
-// ^-- OR: import russianLocale from '@uppy/locales/lib/ru_RU'
-const uppy = new Uppy({
- locale: russianLocale,
-})
-```
-
-If you use Uppy from a CDN, [there’s an example](/examples/i18n/) showcasing how to change languages.
-
-For flexibility, you can pass a `locale` at the `Uppy`/core level, or to Plugins individually. The locale strings that you set in core take precedence.
-
-It also offers the pluralization function, which is used to figure which string will be used for the provided `smart_count` number.
-
-For example, for the Icelandic language, the pluralization function would be:
+}
-```js
-const uppy = new Uppy({
- locale: {
- pluralize: (n) => ((n % 10 !== 1 || n % 100 === 11) ? 1 : 0),
- },
-})
```
-We are using a forked [Polyglot.js](https://github.com/airbnb/polyglot.js/blob/master/index.js#L37-L60).
-
### `store: defaultStore()`
The Store that is used to keep track of internal state. By [default](/docs/stores/#DefaultStore), a plain object is used.
diff --git a/website/src/docs/dashboard.md b/website/src/docs/dashboard.md
index 6ba45f8fd2..87ddd9c537 100644
--- a/website/src/docs/dashboard.md
+++ b/website/src/docs/dashboard.md
@@ -333,104 +333,98 @@ Dashboard ships with the `ThumbnailGenerator` plugin that adds small resized ima
### `locale: {}`
-Localize text that is shown to the user.
-
-The Dashboard also includes the [`@uppy/status-bar`](/docs/status-bar) plugin by default, which has its own strings. Strings for the Status Bar can also be specified in the Dashboard `locale.strings` option, and will be passed down. They are not all listed below—see the [`@uppy/status-bar`](/docs/status-bar) documentation pages for the full list.
-
-The default English strings are:
+
```js
-const strings = {
- // When `inline: false`, used as the screen reader label for the button that closes the modal.
- closeModal: 'Close Modal',
- // Used as the screen reader label for the plus (+) button that shows the “Add more files” screen
- addMoreFiles: 'Add more files',
- // TODO
- addingMoreFiles: 'Adding more files',
- // Used as the header for import panels, e.g., “Import from Google Drive”.
- importFrom: 'Import from %{name}',
- // When `inline: false`, used as the screen reader label for the dashboard modal.
- dashboardWindowTitle: 'Uppy Dashboard Window (Press escape to close)',
- // When `inline: true`, used as the screen reader label for the dashboard area.
- dashboardTitle: 'Uppy Dashboard',
- // Shown in the Informer when a link to a file was copied to the clipboard.
- copyLinkToClipboardSuccess: 'Link copied to clipboard.',
- // Used when a link cannot be copied automatically — the user has to select the text from the
- // input element below this string.
- copyLinkToClipboardFallback: 'Copy the URL below',
- // Used as the hover title and screen reader label for buttons that copy a file link.
- copyLink: 'Copy link',
- // Used as the hover title and screen reader label for file source icons, e.g., “File source: Dropbox”.
- fileSource: 'File source: %{name}',
- // Used as the label for buttons that accept and close panels (remote providers or metadata editor)
- done: 'Done',
- // TODO
- back: 'Back',
- // Used as the screen reader label for buttons that remove a file.
- removeFile: 'Remove file',
- // Used as the screen reader label for buttons that open the metadata editor panel for a file.
- editFile: 'Edit file',
- // Shown in the panel header for the metadata editor. Rendered as “Editing image.png”.
- editing: 'Editing %{file}',
- // Text for a button shown on the file preview, used to edit file metadata
- edit: 'Edit',
- // Used as the screen reader label for the button that saves metadata edits and returns to the
- // file list view.
- finishEditingFile: 'Finish editing file',
- // TODO
- saveChanges: 'Save changes',
- // Used as the label for the tab button that opens the system file selection dialog.
- myDevice: 'My Device',
- // Shown in the main dashboard area when no files have been selected, and one or more
- // remote provider plugins are in use. %{browse} is replaced with a link that opens the system
- // file selection dialog.
- dropPasteImport: 'Drop files here, paste, %{browse} or import from',
- // Shown in the main dashboard area when no files have been selected, and no provider
- // plugins are in use. %{browse} is replaced with a link that opens the system
- // file selection dialog.
- dropPaste: 'Drop files here, paste or %{browse}',
- // TODO
- dropHint: 'Drop your files here',
- // This string is clickable and opens the system file selection dialog.
- browse: 'browse',
- // Used as the hover text and screen reader label for file progress indicators when
- // they have been fully uploaded.
- uploadComplete: 'Upload complete',
- // TODO
- uploadPaused: 'Upload paused',
- // Used as the hover text and screen reader label for the buttons to resume paused uploads.
- resumeUpload: 'Resume upload',
- // Used as the hover text and screen reader label for the buttons to pause uploads.
- pauseUpload: 'Pause upload',
- // Used as the hover text and screen reader label for the buttons to retry failed uploads.
- retryUpload: 'Retry upload',
- // Used as the hover text and screen reader label for the buttons to cancel uploads.
- cancelUpload: 'Cancel upload',
-
- // Used in a title, how many files are currently selected
- xFilesSelected: {
- 0: '%{smart_count} file selected',
- 1: '%{smart_count} files selected',
- },
- // TODO
- uploadingXFiles: {
- 0: 'Uploading %{smart_count} file',
- 1: 'Uploading %{smart_count} files',
- },
- // TODO
- processingXFiles: {
- 0: 'Processing %{smart_count} file',
- 1: 'Processing %{smart_count} files',
+module.exports = {
+ strings: {
+ // When `inline: false`, used as the screen reader label for the button that closes the modal.
+ closeModal: 'Close Modal',
+ // Used as the screen reader label for the plus (+) button that shows the “Add more files” screen
+ addMoreFiles: 'Add more files',
+ addingMoreFiles: 'Adding more files',
+ // Used as the header for import panels, e.g., “Import from Google Drive”.
+ importFrom: 'Import from %{name}',
+ // When `inline: false`, used as the screen reader label for the dashboard modal.
+ dashboardWindowTitle: 'Uppy Dashboard Window (Press escape to close)',
+ // When `inline: true`, used as the screen reader label for the dashboard area.
+ dashboardTitle: 'Uppy Dashboard',
+ // Shown in the Informer when a link to a file was copied to the clipboard.
+ copyLinkToClipboardSuccess: 'Link copied to clipboard.',
+ // Used when a link cannot be copied automatically — the user has to select the text from the
+ // input element below this string.
+ copyLinkToClipboardFallback: 'Copy the URL below',
+ // Used as the hover title and screen reader label for buttons that copy a file link.
+ copyLink: 'Copy link',
+ back: 'Back',
+ // Used as the screen reader label for buttons that remove a file.
+ removeFile: 'Remove file',
+ // Used as the screen reader label for buttons that open the metadata editor panel for a file.
+ editFile: 'Edit file',
+ // Shown in the panel header for the metadata editor. Rendered as “Editing image.png”.
+ editing: 'Editing %{file}',
+ // Used as the screen reader label for the button that saves metadata edits and returns to the
+ // file list view.
+ finishEditingFile: 'Finish editing file',
+ saveChanges: 'Save changes',
+ // Used as the label for the tab button that opens the system file selection dialog.
+ myDevice: 'My Device',
+ dropHint: 'Drop your files here',
+ // Used as the hover text and screen reader label for file progress indicators when
+ // they have been fully uploaded.
+ uploadComplete: 'Upload complete',
+ uploadPaused: 'Upload paused',
+ // Used as the hover text and screen reader label for the buttons to resume paused uploads.
+ resumeUpload: 'Resume upload',
+ // Used as the hover text and screen reader label for the buttons to pause uploads.
+ pauseUpload: 'Pause upload',
+ // Used as the hover text and screen reader label for the buttons to retry failed uploads.
+ retryUpload: 'Retry upload',
+ // Used as the hover text and screen reader label for the buttons to cancel uploads.
+ cancelUpload: 'Cancel upload',
+ // Used in a title, how many files are currently selected
+ xFilesSelected: {
+ 0: '%{smart_count} file selected',
+ 1: '%{smart_count} files selected',
+ },
+ uploadingXFiles: {
+ 0: 'Uploading %{smart_count} file',
+ 1: 'Uploading %{smart_count} files',
+ },
+ processingXFiles: {
+ 0: 'Processing %{smart_count} file',
+ 1: 'Processing %{smart_count} files',
+ },
+ // The "powered by Uppy" link at the bottom of the Dashboard.
+ poweredBy: 'Powered by %{uppy}',
+ addMore: 'Add more',
+ editFileWithFilename: 'Edit file %{file}',
+ save: 'Save',
+ cancel: 'Cancel',
+ dropPasteFiles: 'Drop files here or %{browseFiles}',
+ dropPasteFolders: 'Drop files here or %{browseFolders}',
+ dropPasteBoth: 'Drop files here, %{browseFiles} or %{browseFolders}',
+ dropPasteImportFiles: 'Drop files here, %{browseFiles} or import from:',
+ dropPasteImportFolders: 'Drop files here, %{browseFolders} or import from:',
+ dropPasteImportBoth:
+ 'Drop files here, %{browseFiles}, %{browseFolders} or import from:',
+ importFiles: 'Import files from:',
+ browseFiles: 'browse files',
+ browseFolders: 'browse folders',
+ recoveredXFiles: {
+ 0: 'We could not fully recover 1 file. Please re-select it and resume the upload.',
+ 1: 'We could not fully recover %{smart_count} files. Please re-select them and resume the upload.',
+ },
+ recoveredAllFiles: 'We restored all files. You can now resume the upload.',
+ sessionRestored: 'Session restored',
+ reSelect: 'Re-select',
+ missingRequiredMetaFields: {
+ 0: 'Missing required meta field: %{fields}.',
+ 1: 'Missing required meta fields: %{fields}.',
+ },
},
-
- // The "powered by Uppy" link at the bottom of the Dashboard.
- poweredBy: 'Powered by %{uppy}',
-
- // @uppy/status-bar strings:
- uploading: 'Uploading',
- complete: 'Complete',
- // ...etc
}
+
```
### `theme: 'light'`
diff --git a/website/src/docs/dragdrop.md b/website/src/docs/drag-drop.md
similarity index 90%
rename from website/src/docs/dragdrop.md
rename to website/src/docs/drag-drop.md
index f28a8f07b7..1e432aea79 100644
--- a/website/src/docs/dragdrop.md
+++ b/website/src/docs/drag-drop.md
@@ -86,7 +86,20 @@ Optionally, specify a string of text that explains something about the upload fo
### `locale: {}`
-Localize text that is shown to the user.
+
+
+```js
+module.exports = {
+ strings: {
+ // Text to show on the droppable area.
+ // `%{browse}` is replaced with a link that opens the system file selection dialog.
+ dropHereOr: 'Drop here or %{browse}',
+ // Used as the label for the link that opens the system file selection dialog.
+ browse: 'browse',
+ },
+}
+
+```
### `onDragOver(event)`
diff --git a/website/src/docs/dropbox.md b/website/src/docs/dropbox.md
index c4a7b352b4..f898684ff0 100644
--- a/website/src/docs/dropbox.md
+++ b/website/src/docs/dropbox.md
@@ -127,14 +127,13 @@ This option correlates to the [RequestCredentials value](https://developer.mozil
### `locale: {}`
-Localize text that is shown to the user.
-
-The default English strings are:
+
```js
-const locale = {
+module.exports = {
strings: {
- // TODO
+ pluginNameDropbox: 'Dropbox',
},
}
+
```
diff --git a/website/src/docs/facebook.md b/website/src/docs/facebook.md
index 79b9a31a6c..540bf2916e 100644
--- a/website/src/docs/facebook.md
+++ b/website/src/docs/facebook.md
@@ -86,14 +86,13 @@ This option correlates to the [RequestCredentials value](https://developer.mozil
### `locale: {}`
-Localize text that is shown to the user.
-
-The default English strings are:
+
```js
-const locale = {
+module.exports = {
strings: {
- // TODO
+ pluginNameFacebook: 'Facebook',
},
}
+
```
diff --git a/website/src/docs/fileinput.md b/website/src/docs/file-input.md
similarity index 92%
rename from website/src/docs/fileinput.md
rename to website/src/docs/file-input.md
index 21aa49111c..6ebe958b5d 100644
--- a/website/src/docs/fileinput.md
+++ b/website/src/docs/file-input.md
@@ -84,14 +84,18 @@ The `name` attribute for the `` element.
### `locale: {}`
-When `pretty` is set, specify a custom label for the button.
+
```js
-const locale = {
+module.exports = {
strings: {
+ // The same key is used for the same purpose by @uppy/robodog's `form()` API, but our
+ // locale pack scripts can't access it in Robodog. If it is updated here, it should
+ // also be updated there!
chooseFiles: 'Choose files',
},
}
+
```
## Custom file input
diff --git a/website/src/docs/google-drive.md b/website/src/docs/google-drive.md
index ab56cfb3cc..dabb2e830e 100644
--- a/website/src/docs/google-drive.md
+++ b/website/src/docs/google-drive.md
@@ -122,14 +122,13 @@ This option correlates to the [RequestCredentials value](https://developer.mozil
### `locale: {}`
-Localize text that is shown to the user.
-
-The default English strings are:
+
```js
-const locale = {
- strings:{
- // TODO
+module.exports = {
+ strings: {
+ pluginNameGoogleDrive: 'Google Drive',
},
}
+
```
diff --git a/website/src/docs/instagram.md b/website/src/docs/instagram.md
index c35995f79b..72a2cf98bb 100644
--- a/website/src/docs/instagram.md
+++ b/website/src/docs/instagram.md
@@ -92,14 +92,13 @@ This option correlates to the [RequestCredentials value](https://developer.mozil
### `locale: {}`
-Localize text that is shown to the user.
-
-The default English strings are:
+
```js
-const locale = {
+module.exports = {
strings: {
- // TODO
+ pluginNameInstagram: 'Instagram',
},
}
+
```
diff --git a/website/src/docs/onedrive.md b/website/src/docs/onedrive.md
index 28fe5bc123..34903da5ad 100644
--- a/website/src/docs/onedrive.md
+++ b/website/src/docs/onedrive.md
@@ -86,14 +86,13 @@ This option correlates to the [RequestCredentials value](https://developer.mozil
### `locale: {}`
-Localize text that is shown to the user.
-
-The default English strings are:
+
```js
-const locale = {
+module.exports = {
strings: {
- // TODO
+ pluginNameOneDrive: 'OneDrive',
},
}
+
```
diff --git a/website/src/docs/screen-capture.md b/website/src/docs/screen-capture.md
index ea9a819dcd..60b1d7fcdf 100644
--- a/website/src/docs/screen-capture.md
+++ b/website/src/docs/screen-capture.md
@@ -101,3 +101,20 @@ Set the preferred mime type for video recordings, for example `'video/webm'`. If
If no preferred video mime type is given, the ScreenCapture plugin will prefer types listed in the [`allowedFileTypes` restriction](/docs/uppy/#restrictions), if any.
### `locale: {}`
+
+
+
+```js
+module.exports = {
+ strings: {
+ startCapturing: 'Begin screen capturing',
+ stopCapturing: 'Stop screen capturing',
+ submitRecordedFile: 'Submit recorded file',
+ streamActive: 'Stream active',
+ streamPassive: 'Stream passive',
+ micDisabled: 'Microphone access denied by user',
+ recording: 'Recording',
+ },
+}
+
+```
diff --git a/website/src/docs/statusbar.md b/website/src/docs/status-bar.md
similarity index 66%
rename from website/src/docs/statusbar.md
rename to website/src/docs/status-bar.md
index bffbd7863c..8824489bf5 100644
--- a/website/src/docs/statusbar.md
+++ b/website/src/docs/status-bar.md
@@ -120,51 +120,58 @@ const doneButtonHandler = () => {
### `locale: {}`
-Localize text that is shown to the user.
-
-The default English strings are:
+
```js
-const strings = {
- // Shown in the status bar while files are being uploaded.
- uploading: 'Uploading',
- // Shown in the status bar once all files have been uploaded.
- complete: 'Complete',
- // Shown in the status bar if an upload failed.
- uploadFailed: 'Upload failed',
- // Shown in the status bar while the upload is paused.
- paused: 'Paused',
- // Used as the label for the button that retries an upload.
- retry: 'Retry',
- // Used as the label for the button that cancels an upload.
- cancel: 'Cancel',
- // Used as the label for the button that pauses an upload.
- pause: 'Pause',
- // Used as the label for the button that resumes an upload.
- resume: 'Resume',
- // Used as the label for the button that resets the upload state after an upload
- done: 'Done',
- // When `showProgressDetails` is set, shows the number of files that have been fully uploaded so far.
- filesUploadedOfTotal: {
- 0: '%{complete} of %{smart_count} file uploaded',
- 1: '%{complete} of %{smart_count} files uploaded',
- },
- // When `showProgressDetails` is set, shows the amount of bytes that have been uploaded so far.
- dataUploadedOfTotal: '%{complete} of %{total}',
- // When `showProgressDetails` is set, shows an estimation of how long the upload will take to complete.
- xTimeLeft: '%{time} left',
- // Used as the label for the button that starts an upload.
- uploadXFiles: {
- 0: 'Upload %{smart_count} file',
- 1: 'Upload %{smart_count} files',
- },
- // Used as the label for the button that starts an upload, if another upload has been started in the past
- // and new files were added later.
- uploadXNewFiles: {
- 0: 'Upload +%{smart_count} file',
- 1: 'Upload +%{smart_count} files',
+module.exports = {
+ strings: {
+ // Shown in the status bar while files are being uploaded.
+ uploading: 'Uploading',
+ // Shown in the status bar once all files have been uploaded.
+ complete: 'Complete',
+ // Shown in the status bar if an upload failed.
+ uploadFailed: 'Upload failed',
+ // Shown in the status bar while the upload is paused.
+ paused: 'Paused',
+ // Used as the label for the button that retries an upload.
+ retry: 'Retry',
+ // Used as the label for the button that cancels an upload.
+ cancel: 'Cancel',
+ // Used as the label for the button that pauses an upload.
+ pause: 'Pause',
+ // Used as the label for the button that resumes an upload.
+ resume: 'Resume',
+ // Used as the label for the button that resets the upload state after an upload
+ done: 'Done',
+ // When `showProgressDetails` is set, shows the number of files that have been fully uploaded so far.
+ filesUploadedOfTotal: {
+ 0: '%{complete} of %{smart_count} file uploaded',
+ 1: '%{complete} of %{smart_count} files uploaded',
+ },
+ // When `showProgressDetails` is set, shows the amount of bytes that have been uploaded so far.
+ dataUploadedOfTotal: '%{complete} of %{total}',
+ // When `showProgressDetails` is set, shows an estimation of how long the upload will take to complete.
+ xTimeLeft: '%{time} left',
+ // Used as the label for the button that starts an upload.
+ uploadXFiles: {
+ 0: 'Upload %{smart_count} file',
+ 1: 'Upload %{smart_count} files',
+ },
+ // Used as the label for the button that starts an upload, if another upload has been started in the past
+ // and new files were added later.
+ uploadXNewFiles: {
+ 0: 'Upload +%{smart_count} file',
+ 1: 'Upload +%{smart_count} files',
+ },
+ upload: 'Upload',
+ retryUpload: 'Retry upload',
+ xMoreFilesAdded: {
+ 0: '%{smart_count} more file added',
+ 1: '%{smart_count} more files added',
+ },
},
}
+
```
[`@uppy/file-input`]: /docs/file-input
diff --git a/website/src/docs/transloadit.md b/website/src/docs/transloadit.md
index 73a16cf1e6..5559fb9532 100644
--- a/website/src/docs/transloadit.md
+++ b/website/src/docs/transloadit.md
@@ -275,20 +275,21 @@ Limit the amount of uploads going on at the same time. Setting this to `0` means
### `locale: {}`
-Localize text that is shown to the user.
-
-The default English strings are:
+
```js
-const strings = {
- // Shown while Assemblies are being created for an upload.
- creatingAssembly: 'Preparing upload...',
- // Shown if an Assembly could not be created.
- creatingAssemblyFailed: 'Transloadit: Could not create Assembly',
- // Shown after uploads have succeeded, but when the Assembly is still executing.
- // This only shows if `waitForMetadata` or `waitForEncoding` was enabled.
- encoding: 'Encoding...',
+module.exports = {
+ strings: {
+ // Shown while Assemblies are being created for an upload.
+ creatingAssembly: 'Preparing upload...',
+ // Shown if an Assembly could not be created.
+ creatingAssemblyFailed: 'Transloadit: Could not create Assembly',
+ // Shown after uploads have succeeded, but when the Assembly is still executing.
+ // This only shows if `waitForMetadata` or `waitForEncoding` was enabled.
+ encoding: 'Encoding...',
+ },
}
+
```
## Errors
diff --git a/website/src/docs/url.md b/website/src/docs/url.md
index d4ced72267..a2853e493a 100644
--- a/website/src/docs/url.md
+++ b/website/src/docs/url.md
@@ -84,21 +84,22 @@ This option correlates to the [RequestCredentials value](https://developer.mozil
### `locale: {}`
-Localize text that is shown to the user.
-
-The default English strings are:
+
```js
-const strings = {
- // Label for the "Import" button.
- import: 'Import',
- // Placeholder text for the URL input.
- enterUrlToImport: 'Enter URL to import a file',
- // Error message shown if Companion could not load a URL.
- failedToFetch: 'Companion failed to fetch this URL, please make sure it’s correct',
- // Error message shown if the input does not look like a URL.
- enterCorrectUrl: 'Incorrect URL: Please make sure you are entering a direct link to a file',
+module.exports = {
+ strings: {
+ // Label for the "Import" button.
+ import: 'Import',
+ // Placeholder text for the URL input.
+ enterUrlToImport: 'Enter URL to import a file',
+ // Error message shown if Companion could not load a URL.
+ failedToFetch: 'Companion failed to fetch this URL, please make sure it’s correct',
+ // Error message shown if the input does not look like a URL.
+ enterCorrectUrl: 'Incorrect URL: Please make sure you are entering a direct link to a file',
+ },
}
+
```
## Methods
diff --git a/website/src/docs/webcam.md b/website/src/docs/webcam.md
index 90d10a26d8..46814badfb 100644
--- a/website/src/docs/webcam.md
+++ b/website/src/docs/webcam.md
@@ -150,29 +150,36 @@ If no preferred image mime type is given, the Webcam plugin will prefer types li
### `locale: {}`
-Localize text that is shown to the user.
-
-The default English strings are:
+
```js
-const strings = {
- // Shown before a picture is taken when the `countdown` option is set.
- smile: 'Smile!',
- // Used as the label for the button that takes a picture.
- // This is not visibly rendered but is picked up by screen readers.
- takePicture: 'Take a picture',
- // Used as the label for the button that starts a video recording.
- // This is not visibly rendered but is picked up by screen readers.
- startRecording: 'Begin video recording',
- // Used as the label for the button that stops a video recording.
- // This is not visibly rendered but is picked up by screen readers.
- stopRecording: 'Stop video recording',
- // Used as the label for the recording length counter. See the showRecordingLength option.
- // This is not visibly rendered but is picked up by screen readers.
- recordingLength: 'Recording length %{recording_length}',
- // Title on the “allow access” screen
- allowAccessTitle: 'Please allow access to your camera',
- // Description on the “allow access” screen
- allowAccessDescription: 'In order to take pictures or record video with your camera, please allow camera access for this site.',
+module.exports = {
+ strings: {
+ pluginNameCamera: 'Camera',
+ noCameraTitle: 'Camera Not Available',
+ noCameraDescription: 'In order to take pictures or record video, please connect a camera device',
+ recordingStoppedMaxSize: 'Recording stopped because the file size is about to exceed the limit',
+ submitRecordedFile: 'Submit recorded file',
+ discardRecordedFile: 'Discard recorded file',
+ // Shown before a picture is taken when the `countdown` option is set.
+ smile: 'Smile!',
+ // Used as the label for the button that takes a picture.
+ // This is not visibly rendered but is picked up by screen readers.
+ takePicture: 'Take a picture',
+ // Used as the label for the button that starts a video recording.
+ // This is not visibly rendered but is picked up by screen readers.
+ startRecording: 'Begin video recording',
+ // Used as the label for the button that stops a video recording.
+ // This is not visibly rendered but is picked up by screen readers.
+ stopRecording: 'Stop video recording',
+ // Used as the label for the recording length counter. See the showRecordingLength option.
+ // This is not visibly rendered but is picked up by screen readers.
+ recordingLength: 'Recording length %{recording_length}',
+ // Title on the “allow access” screen
+ allowAccessTitle: 'Please allow access to your camera',
+ // Description on the “allow access” screen
+ allowAccessDescription: 'In order to take pictures or record video with your camera, please allow camera access for this site.',
+ },
}
+
```
diff --git a/website/src/docs/xhrupload.md b/website/src/docs/xhr-upload.md
similarity index 97%
rename from website/src/docs/xhrupload.md
rename to website/src/docs/xhr-upload.md
index 8bacab1f11..2b7fb6ab93 100644
--- a/website/src/docs/xhrupload.md
+++ b/website/src/docs/xhr-upload.md
@@ -231,15 +231,16 @@ Indicates whether cross-site Access-Control requests should be made using creden
### `locale: {}`
-Localize text that is shown to the user.
-
-The default English strings are:
+
```js
-const strings = {
- // Shown in the Informer if an upload is being canceled because it stalled for too long.
- timedOut: 'Upload stalled for %{seconds} seconds, aborting.',
+module.exports = {
+ strings: {
+ // Shown in the Informer if an upload is being canceled because it stalled for too long.
+ timedOut: 'Upload stalled for %{seconds} seconds, aborting.',
+ },
}
+
```
## POST Parameters / Form Fields
diff --git a/website/src/docs/zoom.md b/website/src/docs/zoom.md
index e2726138a0..f871be6bff 100644
--- a/website/src/docs/zoom.md
+++ b/website/src/docs/zoom.md
@@ -90,14 +90,15 @@ This option correlates to the [RequestCredentials value](https://developer.mozil
### `locale: {}`
-Localize text that is shown to the user.
-
-The default English strings are:
+
```js
-const strings = {
- // TODO
+module.exports = {
+ strings: {
+ pluginNameZoom: 'Zoom',
+ },
}
+
```
## Zoom Marketplace
diff --git a/yarn.lock b/yarn.lock
index 3a760ad141..9582b8aa03 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -21451,7 +21451,7 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
-"get-own-enumerable-property-symbols@npm:^3.0.0":
+"get-own-enumerable-property-symbols@npm:^3.0.0, get-own-enumerable-property-symbols@npm:^3.0.2":
version: 3.0.2
resolution: "get-own-enumerable-property-symbols@npm:3.0.2"
checksum: 8f0331f14159f939830884799f937343c8c0a2c330506094bc12cbee3665d88337fe97a4ea35c002cc2bdba0f5d9975ad7ec3abb925015cdf2a93e76d4759ede
@@ -21813,7 +21813,7 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
-"glob@npm:^7.0.0, glob@npm:^7.0.3, glob@npm:^7.0.6, glob@npm:^7.1.0, glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6":
+"glob@npm:^7.0.0, glob@npm:^7.0.3, glob@npm:^7.0.6, glob@npm:^7.1.0, glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.2.0":
version: 7.2.0
resolution: "glob@npm:7.2.0"
dependencies:
@@ -24625,6 +24625,13 @@ hexo-filter-github-emojis@arturi/hexo-filter-github-emojis:
languageName: node
linkType: hard
+"is-obj@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "is-obj@npm:3.0.0"
+ checksum: 75e97a99ed0b0884778887f8e913791864151307774914283b068b06b57ca86f695b024aa1ba5ed04411918edef93e2bfd8f84d68c6b6aab417802cc76f5061b
+ languageName: node
+ linkType: hard
+
"is-object@npm:^1.0.1":
version: 1.0.2
resolution: "is-object@npm:1.0.2"
@@ -24787,6 +24794,13 @@ hexo-filter-github-emojis@arturi/hexo-filter-github-emojis:
languageName: node
linkType: hard
+"is-regexp@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "is-regexp@npm:3.0.0"
+ checksum: c0f32f93accb9408ce1fd3d47f43648b8612d28186638b3a46e835fb147842b220b2ede4bb86315e996a4d78c393b30b0b9ab9348f9be7ab27d4c2b102469c7c
+ languageName: node
+ linkType: hard
+
"is-resolvable@npm:^1.0.0, is-resolvable@npm:^1.1.0":
version: 1.1.0
resolution: "is-resolvable@npm:1.1.0"
@@ -27325,6 +27339,20 @@ hexo-filter-github-emojis@arturi/hexo-filter-github-emojis:
languageName: node
linkType: hard
+"locale-pack@workspace:private/locale-pack":
+ version: 0.0.0-use.local
+ resolution: "locale-pack@workspace:private/locale-pack"
+ dependencies:
+ chalk: ^4.1.2
+ dedent: ^0.7.0
+ glob: ^7.2.0
+ mdast-util-heading-range: ^3.1.0
+ remark: ^14.0.1
+ remark-frontmatter: ^4.0.1
+ stringify-object: ^4.0.0
+ languageName: unknown
+ linkType: soft
+
"localtunnel@npm:^2.0.1":
version: 2.0.2
resolution: "localtunnel@npm:2.0.2"
@@ -28429,6 +28457,17 @@ hexo-filter-github-emojis@arturi/hexo-filter-github-emojis:
languageName: node
linkType: hard
+"mdast-util-heading-range@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "mdast-util-heading-range@npm:3.1.0"
+ dependencies:
+ "@types/mdast": ^3.0.0
+ "@types/unist": ^2.0.0
+ mdast-util-to-string: ^3.0.0
+ checksum: c0f9892cdd36ab88b368f636270e7e846edc3c923a395b6ae49913e99c88cdff9eb5b2b131a9f20e8a78d22aff66e0523acda630721f30d8e32159ca6d35ac5d
+ languageName: node
+ linkType: hard
+
"mdast-util-heading-style@npm:^2.0.0":
version: 2.0.0
resolution: "mdast-util-heading-style@npm:2.0.0"
@@ -36261,6 +36300,18 @@ hexo-filter-github-emojis@arturi/hexo-filter-github-emojis:
languageName: node
linkType: hard
+"remark-frontmatter@npm:^4.0.1":
+ version: 4.0.1
+ resolution: "remark-frontmatter@npm:4.0.1"
+ dependencies:
+ "@types/mdast": ^3.0.0
+ mdast-util-frontmatter: ^1.0.0
+ micromark-extension-frontmatter: ^1.0.0
+ unified: ^10.0.0
+ checksum: c1c448923cd0239e9eeafb42d7129c05081c9a1bca4c8164b562cbb748e80d103bfd058597a48d54000ce3c776200ab8ccd64a9679d955423f07e4a4e77f10c3
+ languageName: node
+ linkType: hard
+
"remark-lint-emphasis-marker@npm:^3.0.0":
version: 3.1.0
resolution: "remark-lint-emphasis-marker@npm:3.1.0"
@@ -36697,7 +36748,7 @@ hexo-filter-github-emojis@arturi/hexo-filter-github-emojis:
languageName: node
linkType: hard
-"remark@npm:^14.0.0":
+"remark@npm:^14.0.0, remark@npm:^14.0.1":
version: 14.0.1
resolution: "remark@npm:14.0.1"
dependencies:
@@ -39679,6 +39730,17 @@ resolve@^2.0.0-next.3:
languageName: node
linkType: hard
+"stringify-object@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "stringify-object@npm:4.0.0"
+ dependencies:
+ get-own-enumerable-property-symbols: ^3.0.2
+ is-obj: ^3.0.0
+ is-regexp: ^3.0.0
+ checksum: 8fffae04044f0a4f7fa70e05b857750e35a54e6117cdf69cad2d1ef318ff4b0c8fec57a7731646fca0ca7c07ae723cb12edbbbc863377607aec9c83adb9ff5a3
+ languageName: node
+ linkType: hard
+
"strip-ansi@npm:6.0.0":
version: 6.0.0
resolution: "strip-ansi@npm:6.0.0"