소스 검색

Default locale for all plugins (#1443)

* first swing at building locale pack

* expose default locale on the plugin instance

* write a pretty en_US locale to a file, using stringify-object and template.js

* generated locale pack

* start adding a script that checks for unused locale strings

Co-Authored-By: Kevin van Zonneveld <kevin@transloadit.com>

* Update bin/build-locale-pack.js

* Console output improvements

* Also sort plugin locale keys

* Support dependencies when digging up sources

because e.g. 'emptyFolderAdded' is used in provider-views but set in Dashboard's defaultLocale

* More complex matching

So can can support cases like: `uppy.i18n(error.isAuthError ? 'companionAuthError' : 'companionError')`

* Remaining const defaultLocale -> this.defaultLocale

* Update packages/@uppy/locales/en_US.js

* Mock browser environment so all plugins can be instantiated

* Clean up output a bit

* Update bin/build-locale-pack.js

* Add all remaining plugin's locales to en_US bundle

* Update packages/@uppy/dashboard/src/index.js

* Update en_US.js

Co-Authored-By: Kevin van Zonneveld <kevin@transloadit.com>

* remove unused strings

Co-Authored-By: Kevin van Zonneveld <kevin@transloadit.com>

* Also write csv because that makes it real easy to import to friendlier places for translators /cc @arturi

* don’t set locale: this.defaultLocale — it overrides the lang pack

Co-Authored-By: Kevin van Zonneveld <kevin@transloadit.com>

* Add 'russian plural' for english, for consistency

Allows us to signal that this is possible in new target languages, and also run better linting

* Cleanup

* No longer write csv

* WIP for NL

* Create package.json

Co-Authored-By: Kevin van Zonneveld <kevin@transloadit.com>

* move locales to /src

Co-Authored-By: Kevin van Zonneveld <kevin@transloadit.com>

* ignore locales themselves

Co-Authored-By: Kevin van Zonneveld <kevin@transloadit.com>

* build minified locale packs

Co-Authored-By: Kevin van Zonneveld <kevin@transloadit.com>

* expose Uppy.locale = {} placeholder object

Co-Authored-By: Kevin van Zonneveld <kevin@transloadit.com>

* Update ru_RU.js

Co-Authored-By: Kevin van Zonneveld <kevin@transloadit.com>

* add locale bundles to example

Co-Authored-By: Kevin van Zonneveld <kevin@transloadit.com>

* Upload locales to cdn

* Allow to run tests with upload-to-cdn by setting a versionSuffix

* Move locale build to function, to make room for test()

* Bring ru_RU in sync with English

now that we've added 3 plural types across the board

* Document using locales as a consuming dev, and plugin dev

* Add linting for missing/excess locale strings

* Add the locales we had to remove to the legacy folder

and explain why they cannot make it back

* Move legacy outside of src so they are definitely not transpiled, etc

* Update packages/@uppy/locales/src/nl_NL.js

* Update website/src/docs/uppy.md
Artur Paikin 6 년 전
부모
커밋
28fce1a137
38개의 변경된 파일2376개의 추가작업 그리고 193개의 파일을 삭제
  1. 20 2
      bin/build-bundle.js
  2. 238 0
      bin/locale-packs.js
  3. 57 25
      bin/upload-to-cdn.sh
  4. 64 86
      package-lock.json
  5. 6 2
      package.json
  6. 3 4
      packages/@uppy/aws-s3/src/index.js
  7. 8 6
      packages/@uppy/core/src/index.js
  8. 10 21
      packages/@uppy/dashboard/src/index.js
  9. 3 4
      packages/@uppy/drag-drop/src/index.js
  10. 3 4
      packages/@uppy/file-input/src/index.js
  11. 969 0
      packages/@uppy/locales/legacy/README.md
  12. 63 0
      packages/@uppy/locales/legacy/cs_CZ.js
  13. 54 0
      packages/@uppy/locales/legacy/de_DE.js
  14. 54 0
      packages/@uppy/locales/legacy/es_ES.js
  15. 54 0
      packages/@uppy/locales/legacy/fi_FI.js
  16. 54 0
      packages/@uppy/locales/legacy/id_ID.js
  17. 54 0
      packages/@uppy/locales/legacy/it_IT.js
  18. 54 0
      packages/@uppy/locales/legacy/nb_NO.js
  19. 61 0
      packages/@uppy/locales/legacy/pl_PL.js
  20. 52 0
      packages/@uppy/locales/legacy/pt_BR.js
  21. 54 0
      packages/@uppy/locales/legacy/tr_TR.js
  22. 34 0
      packages/@uppy/locales/legacy/zh_CN.js
  23. 19 0
      packages/@uppy/locales/package.json
  24. 143 0
      packages/@uppy/locales/src/en_US.js
  25. 148 0
      packages/@uppy/locales/src/ru_RU.js
  26. 18 0
      packages/@uppy/locales/template.js
  27. 10 14
      packages/@uppy/status-bar/src/index.js
  28. 3 4
      packages/@uppy/transloadit/src/index.js
  29. 3 5
      packages/@uppy/url/src/index.js
  30. 2 3
      packages/@uppy/webcam/src/index.js
  31. 2 3
      packages/@uppy/xhr-upload/src/index.js
  32. 2 0
      packages/uppy/index.js
  33. 4 1
      website/inject.js
  34. 0 3
      website/src/docs/statusbar.md
  35. 15 1
      website/src/docs/uppy.md
  36. 28 1
      website/src/docs/writing-plugins.md
  37. 9 3
      website/src/examples/i18n/app.html
  38. 1 1
      website/src/examples/i18n/index.ejs

+ 20 - 2
bin/build-bundle.js

@@ -5,6 +5,8 @@ var babelify = require('babelify')
 var tinyify = require('tinyify')
 var browserify = require('browserify')
 var exorcist = require('exorcist')
+var glob = require('glob')
+var path = require('path')
 
 function handleErr (err) {
   console.error(chalk.red('✗ Error:'), chalk.red(err.message))
@@ -36,8 +38,9 @@ function buildBundle (srcFile, bundleFile, { minify = false, standalone = '' } =
 
 mkdirp.sync('./packages/uppy/dist')
 mkdirp.sync('./packages/@uppy/robodog/dist')
+mkdirp.sync('./packages/@uppy/locales/dist')
 
-Promise.all([
+const methods = [
   buildBundle(
     './packages/uppy/bundle.js',
     './packages/uppy/dist/uppy.js',
@@ -58,6 +61,21 @@ Promise.all([
     './packages/@uppy/robodog/dist/robodog.min.js',
     { standalone: 'Robodog', minify: true }
   )
-]).then(function () {
+]
+
+// Build minified versions of all the locales
+const localePackagePath = path.join(__dirname, '..', 'packages', '@uppy', 'locales', 'src', '*.js')
+glob.sync(localePackagePath).forEach((localePath) => {
+  const localeName = path.basename(localePath, '.js')
+  methods.push(
+    buildBundle(
+      `./packages/@uppy/locales/src/${localeName}.js`,
+      `./packages/@uppy/locales/dist/${localeName}.min.js`,
+      { minify: true }
+    )
+  )
+})
+
+Promise.all(methods).then(function () {
   console.info(chalk.yellow('✓ JS bundles 🎉'))
 })

+ 238 - 0
bin/locale-packs.js

@@ -0,0 +1,238 @@
+const glob = require('glob')
+const Uppy = require('../packages/@uppy/core')
+const chalk = require('chalk')
+const path = require('path')
+const flat = require('flat')
+const stringifyObject = require('stringify-object')
+const fs = require('fs')
+const uppy = Uppy()
+let localePack = {}
+const plugins = {}
+const sources = {}
+
+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') {
+  build()
+} else if (mode === 'test') {
+  test()
+} else {
+  throw new Error(`First argument must be either 'build' or 'test'`)
+}
+
+function getSources (pluginName) {
+  const dependencies = {
+    // because e.g. 'companionAuthError' is used in provider-views but set in Core's defaultLocale
+    'core': ['provider-views'],
+    // because e.g. 'emptyFolderAdded' is used in provider-views but set in Dashboard's defaultLocale
+    'dashboard': ['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 () {
+  // 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 (let file of files) {
+    const dirName = path.dirname(file)
+    const pluginName = path.basename(dirName)
+    if (pluginName === 'locales') {
+      continue
+    }
+    const Plugin = require(dirName)
+    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 = {}
+    global.localStorage = {
+      key: () => { },
+      getItem: () => { }
+    }
+    global.window = {
+      indexedDB: {
+        open: () => { return {} }
+      }
+    }
+    global.document = {
+      createElement: () => {
+        return { style: {} }
+      }
+    }
+
+    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 (plugin, pluginName) {
+  const localeStrings = plugin.defaultLocale.strings
+
+  for (let key in 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()
+    }
+    localePack[key] = localeStrings[key]
+  }
+}
+
+function checkForUnused (fileContents, pluginName, localePack) {
+  let buff = fileContents.join('\n')
+  for (let key in localePack) {
+    let 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)}`)
+    }
+  }
+}
+
+function sortObjectAlphabetically (obj, sortFunc) {
+  return Object.keys(obj).sort(sortFunc).reduce(function (result, key) {
+    result[key] = obj[key]
+    return result
+  }, {})
+}
+
+function build () {
+  const { plugins, sources } = buildPluginsList()
+
+  for (let pluginName in plugins) {
+    addLocaleToPack(plugins[pluginName], pluginName)
+  }
+
+  localePack = sortObjectAlphabetically(localePack)
+
+  for (let pluginName in sources) {
+    checkForUnused(sources[pluginName], 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')
+  fs.writeFileSync(localePackagePath, finalLocale, 'utf-8')
+  console.log(`✅ Written '${localePackagePath}'`)
+}
+
+function test () {
+  const leadingLocaleName = 'en_US'
+
+  const followerLocales = {}
+  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.2'
+    followerLocales[localeName] = Object.keys(flat(require(localePath).strings))
+  })
+
+  // Take aside our leading locale: en_US
+  const leadingLocale = followerLocales[leadingLocaleName]
+  delete followerLocales[leadingLocaleName]
+
+  // Compare all follower Locales (RU, DE, etc) with our leader en_US
+  const warnings = []
+  const fatals = []
+  for (let followerName in followerLocales) {
+    let followerLocale = followerLocales[followerName]
+    let missing = leadingLocale.filter((key) => !followerLocale.includes(key))
+    let 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
+      warnings.push(`${chalk.cyan(followerName)} locale has missing string: '${chalk.red(key)}' that is present in ${chalk.cyan(leadingLocaleName)}. `)
+    })
+    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(``)
+  }
+}

+ 57 - 25
bin/upload-to-cdn.sh

@@ -33,6 +33,8 @@ __file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
 __base="$(basename ${__file} .sh)"
 __root="$(cd "$(dirname "${__dir}")" && pwd)"
 
+# versionSuffix="-test2"
+
 function fatal () {
   echo "❌ ${*}";
   exit 1
@@ -66,7 +68,7 @@ pushd "${__root}" > /dev/null 2>&1
     version="${localVersion}"
   fi
 
-  majorVersion=$(echo "${version}" |awk -F. '{print $1}')
+  majorVersion=$(echo "${version}${versionSuffix}" |awk -F. '{print $1}')
 
   echo -n "--> Check if not overwriting an existing tag ... "
   env \
@@ -74,11 +76,11 @@ pushd "${__root}" > /dev/null 2>&1
     AWS_SECRET_ACCESS_KEY="${EDGLY_SECRET}" \
   aws s3 ls \
     --region="us-east-1" \
-  "s3://crates.edgly.net/756b8efaed084669b02cb99d4540d81f/default/releases/uppy/v${version}/uppy.min.css" > /dev/null 2>&1 && fatal "Tag ${version} already exists"
+  "s3://crates.edgly.net/756b8efaed084669b02cb99d4540d81f/default/releases/uppy/v${version}${versionSuffix}/uppy.min.css" > /dev/null 2>&1 && fatal "Tag ${version}${versionSuffix} already exists"
   echo "✅"
 
 
-  echo "--> Obtain relevant npm files for robodog ${version} ... "
+  echo "--> Obtain relevant npm files for robodog ${version}${versionSuffix} ... "
   pushd packages/@uppy/robodog
     if [ -z "${remoteVersion}" ]; then
       npm pack || fatal "Unable to fetch "
@@ -101,13 +103,40 @@ pushd "${__root}" > /dev/null 2>&1
     aws s3 sync \
       --region="us-east-1" \
       --exclude 'node_modules/*' \
-    ./ "s3://crates.edgly.net/756b8efaed084669b02cb99d4540d81f/default/releases/uppy/v${version}"
-    echo "Saved https://transloadit.edgly.net/releases/uppy/v${version}/"
+    ./ "s3://crates.edgly.net/756b8efaed084669b02cb99d4540d81f/default/releases/uppy/v${version}${versionSuffix}"
+    echo "Saved https://transloadit.edgly.net/releases/uppy/v${version}${versionSuffix}/"
   popd > /dev/null 2>&1
   rm -rf /tmp/robodog-to-edgly
 
+  echo "--> Obtain relevant npm files for locales ${version}${versionSuffix} ... "
+  pushd packages/@uppy/locales
+    if [ -z "${remoteVersion}" ]; then
+      npm pack || fatal "Unable to fetch "
+    else
+      npm pack "@uppy/locales@${remoteVersion}"
+    fi
+  popd > /dev/null 2>&1
+  echo "✅"
+  rm -rf /tmp/locales-to-edgly
+  mkdir -p /tmp/locales-to-edgly
+  cp -af "packages/@uppy/locales/uppy-locales-${version}.tgz" /tmp/locales-to-edgly/
+  tar zxvf "packages/@uppy/locales/uppy-locales-${version}.tgz" -C /tmp/locales-to-edgly/
+
+  echo "--> Upload locales to edgly.net CDN"
+  pushd /tmp/locales-to-edgly/package/dist
+    # --delete \
+    env \
+      AWS_ACCESS_KEY_ID="${EDGLY_KEY}" \
+      AWS_SECRET_ACCESS_KEY="${EDGLY_SECRET}" \
+    aws s3 sync \
+      --region="us-east-1" \
+      --exclude 'node_modules/*' \
+    ./ "s3://crates.edgly.net/756b8efaed084669b02cb99d4540d81f/default/releases/uppy/v${version}${versionSuffix}/locales"
+    echo "Saved https://transloadit.edgly.net/releases/uppy/v${version}${versionSuffix}/locales/"
+  popd > /dev/null 2>&1
+  rm -rf /tmp/locales-to-edgly
 
-  echo "--> Obtain relevant npm files for uppy ${version} ... "
+  echo "--> Obtain relevant npm files for uppy ${version}${versionSuffix} ... "
   pushd packages/uppy
     if [ -z "${remoteVersion}" ]; then
       npm pack || fatal "Unable to fetch "
@@ -130,26 +159,29 @@ pushd "${__root}" > /dev/null 2>&1
     aws s3 sync \
       --region="us-east-1" \
       --exclude 'node_modules/*' \
-    ./ "s3://crates.edgly.net/756b8efaed084669b02cb99d4540d81f/default/releases/uppy/v${version}"
-    echo "Saved https://transloadit.edgly.net/releases/uppy/v${version}/"
+    ./ "s3://crates.edgly.net/756b8efaed084669b02cb99d4540d81f/default/releases/uppy/v${version}${versionSuffix}"
+    echo "Saved https://transloadit.edgly.net/releases/uppy/v${version}${versionSuffix}/"
   popd > /dev/null 2>&1
   rm -rf /tmp/uppy-to-edgly
 
-
-  echo "${version}" | env \
-    AWS_ACCESS_KEY_ID="${EDGLY_KEY}" \
-    AWS_SECRET_ACCESS_KEY="${EDGLY_SECRET}" \
-  aws s3 cp \
-    --region="us-east-1" \
-    --content-type="text/plain" \
-  - "s3://crates.edgly.net/756b8efaed084669b02cb99d4540d81f/default/releases/uppy/latest.txt"
-  echo "Saved https://transloadit.edgly.net/releases/uppy/latest.txt"
-  echo "${version}" | env \
-    AWS_ACCESS_KEY_ID="${EDGLY_KEY}" \
-    AWS_SECRET_ACCESS_KEY="${EDGLY_SECRET}" \
-  aws s3 cp \
-    --region="us-east-1" \
-    --content-type="text/plain" \
-  - "s3://crates.edgly.net/756b8efaed084669b02cb99d4540d81f/default/releases/uppy/v${majorVersion}-latest.txt"
-  echo "Saved https://transloadit.edgly.net/releases/uppy/v${majorVersion}-latest.txt"
+  if [ "${versionSuffix}" != "" ]; then
+    echo "Not setting latest version because versionSuffix was set, which is used for testing only"
+  else 
+    echo "${version}" | env \
+      AWS_ACCESS_KEY_ID="${EDGLY_KEY}" \
+      AWS_SECRET_ACCESS_KEY="${EDGLY_SECRET}" \
+    aws s3 cp \
+      --region="us-east-1" \
+      --content-type="text/plain" \
+    - "s3://crates.edgly.net/756b8efaed084669b02cb99d4540d81f/default/releases/uppy/latest.txt"
+    echo "Saved https://transloadit.edgly.net/releases/uppy/latest.txt"
+    echo "${version}" | env \
+      AWS_ACCESS_KEY_ID="${EDGLY_KEY}" \
+      AWS_SECRET_ACCESS_KEY="${EDGLY_SECRET}" \
+    aws s3 cp \
+      --region="us-east-1" \
+      --content-type="text/plain" \
+    - "s3://crates.edgly.net/756b8efaed084669b02cb99d4540d81f/default/releases/uppy/v${majorVersion}-latest.txt"
+    echo "Saved https://transloadit.edgly.net/releases/uppy/v${majorVersion}-latest.txt"
+  fi
 popd > /dev/null 2>&1

+ 64 - 86
package-lock.json

@@ -1748,9 +1748,9 @@
 			"integrity": "sha1-yRNQTT3CgQr61VW1ma6uwsxMZ2g="
 		},
 		"@types/aws-lambda": {
-			"version": "8.10.23",
-			"resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.23.tgz",
-			"integrity": "sha512-erfexxfuc1+T7b4OswooKwpIjpdgEOVz6ZrDDWSR+3v7Kjhs4EVowfUkF9KuLKhpcjz+VVHQ/pWIl7zSVbKbFQ=="
+			"version": "8.10.24",
+			"resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.24.tgz",
+			"integrity": "sha512-9F70bcb2oBGZUZCyisE1Ap3vwgt04uiSmr4s9mhQf89vBrttgraBs2Rc8l9YrKiemCndCH7wxnYNWk5qEuv6rA=="
 		},
 		"@types/aws-serverless-express": {
 			"version": "3.3.0",
@@ -6797,9 +6797,9 @@
 			}
 		},
 		"cron-parser": {
-			"version": "2.10.0",
-			"resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-2.10.0.tgz",
-			"integrity": "sha512-E181Gbg+wYT0hSikwBOokL7VHgJDYUlFsRFHIlnTP8GGefhcIyf8PSc2IXztmghj5mhAZupU0n3jKfEpZVEmVg==",
+			"version": "2.11.0",
+			"resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-2.11.0.tgz",
+			"integrity": "sha512-L5LAGlvq2xmCLErhjQRX8IL5v72y8jhGOaxrarYOhse0kJjJGb/vY/0sV/c7F/SylJGkUIY2iZPPJXZD3glZqA==",
 			"requires": {
 				"is-nan": "^1.2.1",
 				"moment-timezone": "^0.5.23"
@@ -10033,6 +10033,14 @@
 				"async-reduce": "0.0.1",
 				"commondir": "0.0.1",
 				"flat": "~1.0.0"
+			},
+			"dependencies": {
+				"flat": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/flat/-/flat-1.0.0.tgz",
+					"integrity": "sha1-Ad/dW8vBScZrNe1AHh11PxqtjVk=",
+					"dev": true
+				}
 			}
 		},
 		"filename-regex": {
@@ -10124,10 +10132,21 @@
 			}
 		},
 		"flat": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/flat/-/flat-1.0.0.tgz",
-			"integrity": "sha1-Ad/dW8vBScZrNe1AHh11PxqtjVk=",
-			"dev": true
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz",
+			"integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==",
+			"dev": true,
+			"requires": {
+				"is-buffer": "~2.0.3"
+			},
+			"dependencies": {
+				"is-buffer": {
+					"version": "2.0.3",
+					"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz",
+					"integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==",
+					"dev": true
+				}
+			}
 		},
 		"flat-cache": {
 			"version": "1.3.0",
@@ -10641,7 +10660,6 @@
 					"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz",
 					"integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==",
 					"dev": true,
-					"optional": true,
 					"requires": {
 						"safe-buffer": "^5.1.1",
 						"yallist": "^3.0.0"
@@ -10662,7 +10680,6 @@
 					"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
 					"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
 					"dev": true,
-					"optional": true,
 					"requires": {
 						"minimist": "0.0.8"
 					}
@@ -10766,7 +10783,6 @@
 					"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
 					"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
 					"dev": true,
-					"optional": true,
 					"requires": {
 						"wrappy": "1"
 					}
@@ -10862,8 +10878,7 @@
 					"version": "5.1.1",
 					"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
 					"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
-					"dev": true,
-					"optional": true
+					"dev": true
 				},
 				"safer-buffer": {
 					"version": "2.1.2",
@@ -10927,7 +10942,6 @@
 					"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
 					"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
 					"dev": true,
-					"optional": true,
 					"requires": {
 						"ansi-regex": "^2.0.0"
 					}
@@ -10976,15 +10990,13 @@
 					"version": "1.0.2",
 					"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
 					"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
-					"dev": true,
-					"optional": true
+					"dev": true
 				},
 				"yallist": {
 					"version": "3.0.2",
 					"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz",
 					"integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=",
-					"dev": true,
-					"optional": true
+					"dev": true
 				}
 			}
 		},
@@ -11101,9 +11113,9 @@
 			"dev": true
 		},
 		"get-own-enumerable-property-symbols": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-2.0.1.tgz",
-			"integrity": "sha512-TtY/sbOemiMKPRUDDanGCSgBYe7Mf0vbRsWnBZ+9yghpZ1MvcpSpuZFjHdEeY/LZjZy0vdLjS77L6HosisFiug==",
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz",
+			"integrity": "sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==",
 			"dev": true
 		},
 		"get-pkg-repo": {
@@ -16225,11 +16237,11 @@
 			}
 		},
 		"nodemon": {
-			"version": "1.18.10",
-			"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.18.10.tgz",
-			"integrity": "sha512-we51yBb1TfEvZamFchRgcfLbVYgg0xlGbyXmOtbBzDwxwgewYS/YbZ5tnlnsH51+AoSTTsT3A2E/FloUbtH8cQ==",
+			"version": "1.18.11",
+			"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.18.11.tgz",
+			"integrity": "sha512-KdN3tm1zkarlqNo4+W9raU3ihM4H15MVMSE/f9rYDZmFgDHAfAJsomYrHhApAkuUemYjFyEeXlpCOQ2v5gtBEw==",
 			"requires": {
-				"chokidar": "^2.1.0",
+				"chokidar": "^2.1.5",
 				"debug": "^3.1.0",
 				"ignore-by-default": "^1.0.1",
 				"minimatch": "^3.0.4",
@@ -16498,8 +16510,7 @@
 						},
 						"ansi-regex": {
 							"version": "2.1.1",
-							"bundled": true,
-							"optional": true
+							"bundled": true
 						},
 						"aproba": {
 							"version": "1.2.0",
@@ -16517,13 +16528,11 @@
 						},
 						"balanced-match": {
 							"version": "1.0.0",
-							"bundled": true,
-							"optional": true
+							"bundled": true
 						},
 						"brace-expansion": {
 							"version": "1.1.11",
 							"bundled": true,
-							"optional": true,
 							"requires": {
 								"balanced-match": "^1.0.0",
 								"concat-map": "0.0.1"
@@ -16536,18 +16545,15 @@
 						},
 						"code-point-at": {
 							"version": "1.1.0",
-							"bundled": true,
-							"optional": true
+							"bundled": true
 						},
 						"concat-map": {
 							"version": "0.0.1",
-							"bundled": true,
-							"optional": true
+							"bundled": true
 						},
 						"console-control-strings": {
 							"version": "1.1.0",
-							"bundled": true,
-							"optional": true
+							"bundled": true
 						},
 						"core-util-is": {
 							"version": "1.0.2",
@@ -16650,8 +16656,7 @@
 						},
 						"inherits": {
 							"version": "2.0.3",
-							"bundled": true,
-							"optional": true
+							"bundled": true
 						},
 						"ini": {
 							"version": "1.3.5",
@@ -16661,7 +16666,6 @@
 						"is-fullwidth-code-point": {
 							"version": "1.0.0",
 							"bundled": true,
-							"optional": true,
 							"requires": {
 								"number-is-nan": "^1.0.0"
 							}
@@ -16674,20 +16678,17 @@
 						"minimatch": {
 							"version": "3.0.4",
 							"bundled": true,
-							"optional": true,
 							"requires": {
 								"brace-expansion": "^1.1.7"
 							}
 						},
 						"minimist": {
 							"version": "0.0.8",
-							"bundled": true,
-							"optional": true
+							"bundled": true
 						},
 						"minipass": {
 							"version": "2.3.5",
 							"bundled": true,
-							"optional": true,
 							"requires": {
 								"safe-buffer": "^5.1.2",
 								"yallist": "^3.0.0"
@@ -16704,7 +16705,6 @@
 						"mkdirp": {
 							"version": "0.5.1",
 							"bundled": true,
-							"optional": true,
 							"requires": {
 								"minimist": "0.0.8"
 							}
@@ -16777,8 +16777,7 @@
 						},
 						"number-is-nan": {
 							"version": "1.0.1",
-							"bundled": true,
-							"optional": true
+							"bundled": true
 						},
 						"object-assign": {
 							"version": "4.1.1",
@@ -16788,7 +16787,6 @@
 						"once": {
 							"version": "1.4.0",
 							"bundled": true,
-							"optional": true,
 							"requires": {
 								"wrappy": "1"
 							}
@@ -16864,8 +16862,7 @@
 						},
 						"safe-buffer": {
 							"version": "5.1.2",
-							"bundled": true,
-							"optional": true
+							"bundled": true
 						},
 						"safer-buffer": {
 							"version": "2.1.2",
@@ -16895,7 +16892,6 @@
 						"string-width": {
 							"version": "1.0.2",
 							"bundled": true,
-							"optional": true,
 							"requires": {
 								"code-point-at": "^1.0.0",
 								"is-fullwidth-code-point": "^1.0.0",
@@ -16913,7 +16909,6 @@
 						"strip-ansi": {
 							"version": "3.0.1",
 							"bundled": true,
-							"optional": true,
 							"requires": {
 								"ansi-regex": "^2.0.0"
 							}
@@ -16952,13 +16947,11 @@
 						},
 						"wrappy": {
 							"version": "1.0.2",
-							"bundled": true,
-							"optional": true
+							"bundled": true
 						},
 						"yallist": {
 							"version": "3.0.3",
-							"bundled": true,
-							"optional": true
+							"bundled": true
 						}
 					}
 				},
@@ -23099,12 +23092,12 @@
 			}
 		},
 		"stringify-object": {
-			"version": "3.2.2",
-			"resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.2.2.tgz",
-			"integrity": "sha512-O696NF21oLiDy8PhpWu8AEqoZHw++QW6mUv0UvKZe8gWSdSvMXkiLufK7OmnP27Dro4GU5kb9U7JIO0mBuCRQg==",
+			"version": "3.3.0",
+			"resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
+			"integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==",
 			"dev": true,
 			"requires": {
-				"get-own-enumerable-property-symbols": "^2.0.1",
+				"get-own-enumerable-property-symbols": "^3.0.0",
 				"is-obj": "^1.0.1",
 				"is-regexp": "^1.0.0"
 			}
@@ -23161,7 +23154,7 @@
 			"dependencies": {
 				"minimist": {
 					"version": "1.2.0",
-					"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+					"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
 					"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
 					"dev": true
 				}
@@ -25511,8 +25504,7 @@
 						"ansi-regex": {
 							"version": "2.1.1",
 							"bundled": true,
-							"dev": true,
-							"optional": true
+							"dev": true
 						},
 						"aproba": {
 							"version": "1.2.0",
@@ -25555,8 +25547,7 @@
 						"code-point-at": {
 							"version": "1.1.0",
 							"bundled": true,
-							"dev": true,
-							"optional": true
+							"dev": true
 						},
 						"concat-map": {
 							"version": "0.0.1",
@@ -25567,8 +25558,7 @@
 						"console-control-strings": {
 							"version": "1.1.0",
 							"bundled": true,
-							"dev": true,
-							"optional": true
+							"dev": true
 						},
 						"core-util-is": {
 							"version": "1.0.2",
@@ -25685,8 +25675,7 @@
 						"inherits": {
 							"version": "2.0.3",
 							"bundled": true,
-							"dev": true,
-							"optional": true
+							"dev": true
 						},
 						"ini": {
 							"version": "1.3.5",
@@ -25698,7 +25687,6 @@
 							"version": "1.0.0",
 							"bundled": true,
 							"dev": true,
-							"optional": true,
 							"requires": {
 								"number-is-nan": "^1.0.0"
 							}
@@ -25721,14 +25709,12 @@
 						"minimist": {
 							"version": "0.0.8",
 							"bundled": true,
-							"dev": true,
-							"optional": true
+							"dev": true
 						},
 						"minipass": {
 							"version": "2.3.5",
 							"bundled": true,
 							"dev": true,
-							"optional": true,
 							"requires": {
 								"safe-buffer": "^5.1.2",
 								"yallist": "^3.0.0"
@@ -25747,7 +25733,6 @@
 							"version": "0.5.1",
 							"bundled": true,
 							"dev": true,
-							"optional": true,
 							"requires": {
 								"minimist": "0.0.8"
 							}
@@ -25828,8 +25813,7 @@
 						"number-is-nan": {
 							"version": "1.0.1",
 							"bundled": true,
-							"dev": true,
-							"optional": true
+							"dev": true
 						},
 						"object-assign": {
 							"version": "4.1.1",
@@ -25841,7 +25825,6 @@
 							"version": "1.4.0",
 							"bundled": true,
 							"dev": true,
-							"optional": true,
 							"requires": {
 								"wrappy": "1"
 							}
@@ -25927,8 +25910,7 @@
 						"safe-buffer": {
 							"version": "5.1.2",
 							"bundled": true,
-							"dev": true,
-							"optional": true
+							"dev": true
 						},
 						"safer-buffer": {
 							"version": "2.1.2",
@@ -25964,7 +25946,6 @@
 							"version": "1.0.2",
 							"bundled": true,
 							"dev": true,
-							"optional": true,
 							"requires": {
 								"code-point-at": "^1.0.0",
 								"is-fullwidth-code-point": "^1.0.0",
@@ -25984,7 +25965,6 @@
 							"version": "3.0.1",
 							"bundled": true,
 							"dev": true,
-							"optional": true,
 							"requires": {
 								"ansi-regex": "^2.0.0"
 							}
@@ -26028,14 +26008,12 @@
 						"wrappy": {
 							"version": "1.0.2",
 							"bundled": true,
-							"dev": true,
-							"optional": true
+							"dev": true
 						},
 						"yallist": {
 							"version": "3.0.3",
 							"bundled": true,
-							"dev": true,
-							"optional": true
+							"dev": true
 						}
 					}
 				},

+ 6 - 2
package.json

@@ -43,6 +43,7 @@
     "eslint-plugin-standard": "^3.1.0",
     "exorcist": "^1.0.1",
     "fakefile": "0.0.9",
+    "flat": "^4.1.0",
     "github-contributors-list": "1.2.3",
     "glob": "^7.1.3",
     "gzip-size": "^5.0.0",
@@ -67,6 +68,7 @@
     "react-dom": "^16.8.6",
     "redux": "^4.0.1",
     "replace-x": "^1.5.0",
+    "stringify-object": "^3.3.0",
     "temp-write": "^3.4.0",
     "tinyify": "^2.5.0",
     "touch": "^3.1.0",
@@ -85,8 +87,9 @@
     "build:clean": "rm -rf packages/*/lib packages/@uppy/*/lib packages/*/dist packages/@uppy/*/dist",
     "build:companion": "cd ./packages/@uppy/companion && npm run build",
     "build:css": "node ./bin/build-css.js",
-    "build:js": "npm-run-all build:lib build:bundle",
+    "build:js": "npm-run-all build:lib build:locale-pack build:bundle",
     "build:lib": "node ./bin/build-lib.js",
+    "build:locale-pack": "node ./bin/locale-packs.js build",
     "build": "npm-run-all --parallel build:js build:css build:companion --serial size",
     "contributors:fetch": "githubcontrib --owner transloadit --repo uppy --cols 6 $([ \"${GITHUB_TOKEN:-}\" == \"\" ] && echo \"\" || echo \"--authToken ${GITHUB_TOKEN}\") --showlogin true --sortOrder desc",
     "contributors:save": "replace-x -m '<!--contributors-->[\\s\\S]+<!--/contributors-->' \"<!--contributors-->\n## Contributors\n\n$(npm run --silent contributors:fetch)\n<!--/contributors-->\" README.md",
@@ -108,10 +111,11 @@
     "test:endtoend:prepare-ci": "npm-run-all --parallel --race test:endtoend:registry test:endtoend:build-ci",
     "test:endtoend:registry": "verdaccio --listen 4002 --config test/endtoend/verdaccio.yaml",
     "test:endtoend": "npm run test:endtoend:prepare-ci && wdio test/endtoend/wdio.remote.conf.js",
+    "test:locale-packs": "node ./bin/locale-packs.js test",
     "test:type": "tsc -p .",
     "test:unit": "npm run build:lib && jest",
     "test:watch": "jest --watch",
-    "test": "npm-run-all lint test:unit test:type test:companion",
+    "test": "npm-run-all lint test:locale-packs test:unit test:type test:companion",
     "uploadcdn": "bin/upload-to-cdn.sh",
     "version": "./bin/sync-version-numbers",
     "watch:css": "onchange 'packages/**/*.scss' --initial --verbose -- npm run build:css",

+ 3 - 4
packages/@uppy/aws-s3/src/index.js

@@ -34,7 +34,7 @@ module.exports = class AwsS3 extends Plugin {
     this.id = 'AwsS3'
     this.title = 'AWS S3'
 
-    const defaultLocale = {
+    this.defaultLocale = {
       strings: {
         preparingUpload: 'Preparing upload...'
       }
@@ -43,14 +43,13 @@ module.exports = class AwsS3 extends Plugin {
     const defaultOptions = {
       timeout: 30 * 1000,
       limit: 0,
-      getUploadParameters: this.getUploadParameters.bind(this),
-      locale: defaultLocale
+      getUploadParameters: this.getUploadParameters.bind(this)
     }
 
     this.opts = { ...defaultOptions, ...opts }
 
     // i18n
-    this.translator = new Translator([ defaultLocale, this.uppy.locale, this.opts.locale ])
+    this.translator = new Translator([ this.defaultLocale, this.uppy.locale, this.opts.locale ])
     this.i18n = this.translator.translate.bind(this.translator)
     this.i18nArray = this.translator.translateArray.bind(this.translator)
 

+ 8 - 6
packages/@uppy/core/src/index.js

@@ -23,15 +23,17 @@ class Uppy {
   * @param {object} opts — Uppy options
   */
   constructor (opts) {
-    const defaultLocale = {
+    this.defaultLocale = {
       strings: {
         youCanOnlyUploadX: {
           0: 'You can only upload %{smart_count} file',
-          1: 'You can only upload %{smart_count} files'
+          1: 'You can only upload %{smart_count} files',
+          2: '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'
+          1: 'You have to select at least %{smart_count} files',
+          2: 'You have to select at least %{smart_count} files'
         },
         exceedsSize: 'This file exceeds maximum allowed size of',
         youCanOnlyUploadFileTypes: 'You can only upload: %{types}',
@@ -44,7 +46,8 @@ class Uppy {
         noFilesFound: 'You have no files or folders here',
         selectXFiles: {
           0: 'Select %{smart_count} file',
-          1: 'Select %{smart_count} files'
+          1: 'Select %{smart_count} files',
+          2: 'Select %{smart_count} files'
         },
         cancel: 'Cancel',
         logOut: 'Log out',
@@ -68,7 +71,6 @@ class Uppy {
       meta: {},
       onBeforeFileAdded: (currentFile, files) => currentFile,
       onBeforeUpload: (files) => files,
-      locale: defaultLocale,
       store: DefaultStore()
     }
 
@@ -77,7 +79,7 @@ class Uppy {
     this.opts.restrictions = Object.assign({}, defaultOptions.restrictions, this.opts.restrictions)
 
     // i18n
-    this.translator = new Translator([ defaultLocale, this.opts.locale ])
+    this.translator = new Translator([ this.defaultLocale, this.opts.locale ])
     this.locale = this.translator.locale
     this.i18n = this.translator.translate.bind(this.translator)
 

+ 10 - 21
packages/@uppy/dashboard/src/index.js

@@ -51,11 +51,9 @@ module.exports = class Dashboard extends Plugin {
     this.type = 'orchestrator'
     this.modalName = `uppy-Dashboard-${cuid()}`
 
-    const defaultLocale = {
+    this.defaultLocale = {
       strings: {
-        selectToUpload: 'Select files to upload',
         closeModal: 'Close Modal',
-        upload: 'Upload',
         importFrom: 'Import from %{name}',
         addingMoreFiles: 'Adding more files',
         addMoreFiles: 'Add more files',
@@ -68,7 +66,6 @@ module.exports = class Dashboard extends Plugin {
         fileSource: 'File source: %{name}',
         done: 'Done',
         back: 'Back',
-        name: 'Name',
         removeFile: 'Remove file',
         editFile: 'Edit file',
         editing: 'Editing %{file}',
@@ -76,14 +73,10 @@ module.exports = class Dashboard extends Plugin {
         finishEditingFile: 'Finish editing file',
         saveChanges: 'Save changes',
         cancel: 'Cancel',
-        localDisk: 'Local Disk',
         myDevice: 'My Device',
         dropPasteImport: 'Drop files here, paste, %{browse} or import from',
         dropPaste: 'Drop files here, paste or %{browse}',
         browse: 'browse',
-        fileProgress: 'File progress: upload speed and ETA',
-        numberOfSelectedFiles: 'Number of selected files',
-        uploadAllNewFiles: 'Upload all new files',
         emptyFolderAdded: 'No files were added from empty folder',
         uploadComplete: 'Upload complete',
         uploadPaused: 'Upload paused',
@@ -93,27 +86,23 @@ module.exports = class Dashboard extends Plugin {
         cancelUpload: 'Cancel upload',
         xFilesSelected: {
           0: '%{smart_count} file selected',
-          1: '%{smart_count} files selected'
-        },
-        uploadXFiles: {
-          0: 'Upload %{smart_count} file',
-          1: 'Upload %{smart_count} files'
+          1: '%{smart_count} files selected',
+          2: '%{smart_count} files selected'
         },
         uploadingXFiles: {
           0: 'Uploading %{smart_count} file',
-          1: 'Uploading %{smart_count} files'
+          1: 'Uploading %{smart_count} files',
+          2: 'Uploading %{smart_count} files'
         },
         processingXFiles: {
           0: 'Processing %{smart_count} file',
-          1: 'Processing %{smart_count} files'
-        },
-        uploadXNewFiles: {
-          0: 'Upload +%{smart_count} file',
-          1: 'Upload +%{smart_count} files'
+          1: 'Processing %{smart_count} files',
+          2: 'Processing %{smart_count} files'
         },
         folderAdded: {
           0: 'Added %{smart_count} file from %{folder}',
-          1: 'Added %{smart_count} files from %{folder}'
+          1: 'Added %{smart_count} files from %{folder}',
+          2: 'Added %{smart_count} files from %{folder}'
         }
       }
     }
@@ -152,7 +141,7 @@ module.exports = class Dashboard extends Plugin {
     this.opts = { ...defaultOptions, ...opts }
 
     // i18n
-    this.translator = new Translator([ defaultLocale, this.uppy.locale, this.opts.locale ])
+    this.translator = new Translator([ this.defaultLocale, this.uppy.locale, this.opts.locale ])
     this.i18n = this.translator.translate.bind(this.translator)
     this.i18nArray = this.translator.translateArray.bind(this.translator)
 

+ 3 - 4
packages/@uppy/drag-drop/src/index.js

@@ -15,7 +15,7 @@ module.exports = class DragDrop extends Plugin {
     this.id = this.opts.id || 'DragDrop'
     this.title = 'Drag & Drop'
 
-    const defaultLocale = {
+    this.defaultLocale = {
       strings: {
         dropHereOr: 'Drop files here or %{browse}',
         browse: 'browse'
@@ -28,8 +28,7 @@ module.exports = class DragDrop extends Plugin {
       inputName: 'files[]',
       width: '100%',
       height: '100%',
-      note: null,
-      locale: defaultLocale
+      note: null
     }
 
     // Merge default options with the ones set by user
@@ -39,7 +38,7 @@ module.exports = class DragDrop extends Plugin {
     this.isDragDropSupported = this.checkDragDropSupport()
 
     // i18n
-    this.translator = new Translator([ defaultLocale, this.uppy.locale, this.opts.locale ])
+    this.translator = new Translator([ this.defaultLocale, this.uppy.locale, this.opts.locale ])
     this.i18n = this.translator.translate.bind(this.translator)
     this.i18nArray = this.translator.translateArray.bind(this.translator)
 

+ 3 - 4
packages/@uppy/file-input/src/index.js

@@ -10,7 +10,7 @@ module.exports = class FileInput extends Plugin {
     this.title = 'File Input'
     this.type = 'acquirer'
 
-    const defaultLocale = {
+    this.defaultLocale = {
       strings: {
         chooseFiles: 'Choose files'
       }
@@ -20,15 +20,14 @@ module.exports = class FileInput extends Plugin {
     const defaultOptions = {
       target: null,
       pretty: true,
-      inputName: 'files[]',
-      locale: defaultLocale
+      inputName: 'files[]'
     }
 
     // Merge default options with the ones set by user
     this.opts = Object.assign({}, defaultOptions, opts)
 
     // i18n
-    this.translator = new Translator([ defaultLocale, this.uppy.locale, this.opts.locale ])
+    this.translator = new Translator([ this.defaultLocale, this.uppy.locale, this.opts.locale ])
     this.i18n = this.translator.translate.bind(this.translator)
     this.i18nArray = this.translator.translateArray.bind(this.translator)
 

+ 969 - 0
packages/@uppy/locales/legacy/README.md

@@ -0,0 +1,969 @@
+Dear translators! 
+
+We tried to salvage your locales from when we had to remove them [10 months ago](https://github.com/transloadit/uppy/tree/10b19ea79b1fb728d97af89e74edca9d03208a75/locales). Unfortunately, a lot has changed since them, which made them outdated. Here are the issues we found, comparing them to en_US (which is the leading locale).
+
+Any help to restore these locales is greatly appreciated <3
+
+- [ ] cs_CZ locale has missing string: 'addMoreFiles' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'addMoreFiles' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'addingMoreFiles' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'allowAccessDescription' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'allowAccessTitle' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'back' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'cancel' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'cancelUpload' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'chooseFiles' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'companionAuthError' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'companionError' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'complete' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'connectedToInternet' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'copyLink' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'creatingAssembly' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'creatingAssemblyFailed' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'dataUploadedOfTotal' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'dropHereOr' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'edit' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'editFile' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'editing' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'emptyFolderAdded' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'encoding' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'enterCorrectUrl' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'enterUrlToImport' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'exceedsSize' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'failedToFetch' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'failedToUpload' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'fileSource' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'filesUploadedOfTotal.0' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'filesUploadedOfTotal.1' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'filesUploadedOfTotal.2' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'filter' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'finishEditingFile' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'folderAdded.0' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'folderAdded.1' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'folderAdded.2' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'import' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'link' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'logOut' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'myDevice' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'noFilesFound' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'noInternetConnection' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'pause' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'pauseUpload' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'paused' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'preparingUpload' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'processingXFiles.0' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'processingXFiles.1' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'processingXFiles.2' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'removeFile' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'resetFilter' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'resume' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'resumeUpload' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'retry' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'retryUpload' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'saveChanges' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'selectXFiles.0' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'selectXFiles.1' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'selectXFiles.2' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'smile' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'startRecording' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'stopRecording' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'takePicture' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'timedOut' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'uploadComplete' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'uploadFailed' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'uploadPaused' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'uploadXFiles.0' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'uploadXFiles.1' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'uploadXFiles.2' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'uploadXNewFiles.0' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'uploadXNewFiles.1' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'uploadXNewFiles.2' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'uploading' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'uploadingXFiles.0' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'uploadingXFiles.1' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'uploadingXFiles.2' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'xFilesSelected.0' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'xFilesSelected.1' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'xFilesSelected.2' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'xMoreFilesAdded.0' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'xMoreFilesAdded.1' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'xMoreFilesAdded.2' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'xTimeLeft' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'youCanOnlyUploadFileTypes' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'youCanOnlyUploadX.0' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'youCanOnlyUploadX.1' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'youCanOnlyUploadX.2' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'youHaveToAtLeastSelectX.0' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'youHaveToAtLeastSelectX.1' that is present in en_US. 
+- [ ] cs_CZ locale has missing string: 'youHaveToAtLeastSelectX.2' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'addMoreFiles' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'addingMoreFiles' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'allowAccessDescription' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'allowAccessTitle' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'back' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'cancel' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'cancelUpload' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'chooseFiles' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'companionAuthError' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'companionError' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'complete' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'connectedToInternet' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'copyLink' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'creatingAssembly' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'creatingAssemblyFailed' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'dataUploadedOfTotal' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'dropHereOr' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'edit' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'editFile' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'editing' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'emptyFolderAdded' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'encoding' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'enterCorrectUrl' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'enterUrlToImport' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'exceedsSize' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'failedToFetch' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'failedToUpload' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'fileSource' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'filesUploadedOfTotal.0' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'filesUploadedOfTotal.1' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'filesUploadedOfTotal.2' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'filter' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'finishEditingFile' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'folderAdded.0' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'folderAdded.1' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'folderAdded.2' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'import' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'link' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'logOut' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'myDevice' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'noFilesFound' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'noInternetConnection' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'pause' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'pauseUpload' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'paused' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'preparingUpload' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'processingXFiles.0' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'processingXFiles.1' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'processingXFiles.2' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'removeFile' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'resetFilter' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'resume' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'resumeUpload' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'retry' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'retryUpload' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'saveChanges' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'selectXFiles.0' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'selectXFiles.1' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'selectXFiles.2' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'smile' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'startRecording' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'stopRecording' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'takePicture' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'timedOut' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'uploadComplete' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'uploadFailed' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'uploadPaused' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'uploadXFiles.0' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'uploadXFiles.1' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'uploadXFiles.2' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'uploadXNewFiles.0' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'uploadXNewFiles.1' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'uploadXNewFiles.2' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'uploading' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'uploadingXFiles.0' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'uploadingXFiles.1' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'uploadingXFiles.2' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'xFilesSelected.0' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'xFilesSelected.1' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'xFilesSelected.2' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'xMoreFilesAdded.0' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'xMoreFilesAdded.1' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'xMoreFilesAdded.2' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'xTimeLeft' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'youCanOnlyUploadFileTypes' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'youCanOnlyUploadX.0' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'youCanOnlyUploadX.1' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'youCanOnlyUploadX.2' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'youHaveToAtLeastSelectX.0' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'youHaveToAtLeastSelectX.1' that is present in en_US. 
+- [ ] de_DE locale has missing string: 'youHaveToAtLeastSelectX.2' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'addMoreFiles' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'addingMoreFiles' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'allowAccessDescription' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'allowAccessTitle' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'back' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'cancel' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'cancelUpload' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'chooseFiles' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'companionAuthError' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'companionError' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'complete' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'connectedToInternet' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'copyLink' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'creatingAssembly' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'creatingAssemblyFailed' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'dataUploadedOfTotal' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'dropHereOr' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'edit' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'editFile' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'editing' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'emptyFolderAdded' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'encoding' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'enterCorrectUrl' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'enterUrlToImport' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'exceedsSize' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'failedToFetch' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'failedToUpload' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'fileSource' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'filesUploadedOfTotal.0' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'filesUploadedOfTotal.1' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'filesUploadedOfTotal.2' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'filter' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'finishEditingFile' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'folderAdded.0' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'folderAdded.1' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'folderAdded.2' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'import' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'link' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'logOut' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'myDevice' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'noFilesFound' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'noInternetConnection' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'pause' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'pauseUpload' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'paused' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'preparingUpload' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'processingXFiles.0' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'processingXFiles.1' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'processingXFiles.2' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'removeFile' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'resetFilter' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'resume' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'resumeUpload' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'retry' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'retryUpload' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'saveChanges' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'selectXFiles.0' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'selectXFiles.1' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'selectXFiles.2' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'smile' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'startRecording' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'stopRecording' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'takePicture' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'timedOut' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'uploadComplete' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'uploadFailed' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'uploadPaused' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'uploadXFiles.0' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'uploadXFiles.1' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'uploadXFiles.2' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'uploadXNewFiles.0' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'uploadXNewFiles.1' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'uploadXNewFiles.2' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'uploading' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'uploadingXFiles.0' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'uploadingXFiles.1' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'uploadingXFiles.2' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'xFilesSelected.0' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'xFilesSelected.1' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'xFilesSelected.2' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'xMoreFilesAdded.0' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'xMoreFilesAdded.1' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'xMoreFilesAdded.2' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'xTimeLeft' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'youCanOnlyUploadFileTypes' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'youCanOnlyUploadX.0' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'youCanOnlyUploadX.1' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'youCanOnlyUploadX.2' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'youHaveToAtLeastSelectX.0' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'youHaveToAtLeastSelectX.1' that is present in en_US. 
+- [ ] es_ES locale has missing string: 'youHaveToAtLeastSelectX.2' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'addMoreFiles' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'addingMoreFiles' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'allowAccessDescription' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'allowAccessTitle' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'back' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'cancel' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'cancelUpload' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'chooseFiles' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'companionAuthError' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'companionError' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'complete' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'connectedToInternet' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'copyLink' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'creatingAssembly' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'creatingAssemblyFailed' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'dataUploadedOfTotal' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'dropHereOr' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'edit' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'editFile' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'editing' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'emptyFolderAdded' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'encoding' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'enterCorrectUrl' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'enterUrlToImport' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'exceedsSize' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'failedToFetch' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'failedToUpload' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'fileSource' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'filesUploadedOfTotal.0' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'filesUploadedOfTotal.1' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'filesUploadedOfTotal.2' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'filter' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'finishEditingFile' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'folderAdded.0' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'folderAdded.1' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'folderAdded.2' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'import' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'link' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'logOut' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'myDevice' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'noFilesFound' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'noInternetConnection' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'pause' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'pauseUpload' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'paused' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'preparingUpload' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'processingXFiles.0' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'processingXFiles.1' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'processingXFiles.2' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'removeFile' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'resetFilter' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'resume' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'resumeUpload' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'retry' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'retryUpload' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'saveChanges' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'selectXFiles.0' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'selectXFiles.1' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'selectXFiles.2' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'smile' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'startRecording' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'stopRecording' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'takePicture' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'timedOut' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'uploadComplete' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'uploadFailed' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'uploadPaused' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'uploadXFiles.0' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'uploadXFiles.1' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'uploadXFiles.2' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'uploadXNewFiles.0' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'uploadXNewFiles.1' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'uploadXNewFiles.2' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'uploading' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'uploadingXFiles.0' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'uploadingXFiles.1' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'uploadingXFiles.2' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'xFilesSelected.0' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'xFilesSelected.1' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'xFilesSelected.2' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'xMoreFilesAdded.0' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'xMoreFilesAdded.1' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'xMoreFilesAdded.2' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'xTimeLeft' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'youCanOnlyUploadFileTypes' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'youCanOnlyUploadX.0' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'youCanOnlyUploadX.1' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'youCanOnlyUploadX.2' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'youHaveToAtLeastSelectX.0' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'youHaveToAtLeastSelectX.1' that is present in en_US. 
+- [ ] fi_FI locale has missing string: 'youHaveToAtLeastSelectX.2' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'addMoreFiles' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'addingMoreFiles' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'allowAccessDescription' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'allowAccessTitle' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'back' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'cancel' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'cancelUpload' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'chooseFiles' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'companionAuthError' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'companionError' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'complete' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'connectedToInternet' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'copyLink' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'creatingAssembly' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'creatingAssemblyFailed' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'dataUploadedOfTotal' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'dropHereOr' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'edit' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'editFile' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'editing' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'emptyFolderAdded' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'encoding' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'enterCorrectUrl' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'enterUrlToImport' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'exceedsSize' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'failedToFetch' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'failedToUpload' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'fileSource' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'filesUploadedOfTotal.0' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'filesUploadedOfTotal.1' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'filesUploadedOfTotal.2' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'filter' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'finishEditingFile' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'folderAdded.0' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'folderAdded.1' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'folderAdded.2' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'import' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'link' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'logOut' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'myDevice' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'noFilesFound' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'noInternetConnection' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'pause' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'pauseUpload' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'paused' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'preparingUpload' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'processingXFiles.0' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'processingXFiles.1' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'processingXFiles.2' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'removeFile' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'resetFilter' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'resume' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'resumeUpload' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'retry' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'retryUpload' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'saveChanges' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'selectXFiles.0' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'selectXFiles.1' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'selectXFiles.2' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'smile' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'startRecording' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'stopRecording' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'takePicture' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'timedOut' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'uploadComplete' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'uploadFailed' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'uploadPaused' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'uploadXFiles.0' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'uploadXFiles.1' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'uploadXFiles.2' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'uploadXNewFiles.0' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'uploadXNewFiles.1' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'uploadXNewFiles.2' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'uploading' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'uploadingXFiles.0' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'uploadingXFiles.1' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'uploadingXFiles.2' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'xFilesSelected.0' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'xFilesSelected.1' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'xFilesSelected.2' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'xMoreFilesAdded.0' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'xMoreFilesAdded.1' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'xMoreFilesAdded.2' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'xTimeLeft' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'youCanOnlyUploadFileTypes' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'youCanOnlyUploadX.0' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'youCanOnlyUploadX.1' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'youCanOnlyUploadX.2' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'youHaveToAtLeastSelectX.0' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'youHaveToAtLeastSelectX.1' that is present in en_US. 
+- [ ] id_ID locale has missing string: 'youHaveToAtLeastSelectX.2' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'addMoreFiles' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'addingMoreFiles' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'allowAccessDescription' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'allowAccessTitle' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'back' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'cancel' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'cancelUpload' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'chooseFiles' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'companionAuthError' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'companionError' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'complete' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'connectedToInternet' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'copyLink' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'creatingAssembly' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'creatingAssemblyFailed' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'dataUploadedOfTotal' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'dropHereOr' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'edit' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'editFile' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'editing' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'emptyFolderAdded' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'encoding' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'enterCorrectUrl' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'enterUrlToImport' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'exceedsSize' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'failedToFetch' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'failedToUpload' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'fileSource' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'filesUploadedOfTotal.0' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'filesUploadedOfTotal.1' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'filesUploadedOfTotal.2' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'filter' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'finishEditingFile' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'folderAdded.0' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'folderAdded.1' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'folderAdded.2' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'import' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'link' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'logOut' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'myDevice' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'noFilesFound' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'noInternetConnection' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'pause' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'pauseUpload' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'paused' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'preparingUpload' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'processingXFiles.0' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'processingXFiles.1' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'processingXFiles.2' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'removeFile' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'resetFilter' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'resume' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'resumeUpload' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'retry' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'retryUpload' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'saveChanges' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'selectXFiles.0' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'selectXFiles.1' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'selectXFiles.2' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'smile' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'startRecording' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'stopRecording' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'takePicture' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'timedOut' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'uploadComplete' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'uploadFailed' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'uploadPaused' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'uploadXFiles.0' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'uploadXFiles.1' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'uploadXFiles.2' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'uploadXNewFiles.0' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'uploadXNewFiles.1' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'uploadXNewFiles.2' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'uploading' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'uploadingXFiles.0' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'uploadingXFiles.1' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'uploadingXFiles.2' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'xFilesSelected.0' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'xFilesSelected.1' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'xFilesSelected.2' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'xMoreFilesAdded.0' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'xMoreFilesAdded.1' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'xMoreFilesAdded.2' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'xTimeLeft' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'youCanOnlyUploadFileTypes' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'youCanOnlyUploadX.0' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'youCanOnlyUploadX.1' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'youCanOnlyUploadX.2' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'youHaveToAtLeastSelectX.0' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'youHaveToAtLeastSelectX.1' that is present in en_US. 
+- [ ] it_IT locale has missing string: 'youHaveToAtLeastSelectX.2' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'addMoreFiles' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'addingMoreFiles' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'allowAccessDescription' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'allowAccessTitle' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'back' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'cancel' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'cancelUpload' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'chooseFiles' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'companionAuthError' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'companionError' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'complete' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'connectedToInternet' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'copyLink' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'creatingAssembly' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'creatingAssemblyFailed' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'dataUploadedOfTotal' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'dropHereOr' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'edit' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'editFile' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'editing' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'emptyFolderAdded' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'encoding' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'enterCorrectUrl' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'enterUrlToImport' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'exceedsSize' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'failedToFetch' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'failedToUpload' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'fileSource' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'filesUploadedOfTotal.0' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'filesUploadedOfTotal.1' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'filesUploadedOfTotal.2' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'filter' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'finishEditingFile' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'folderAdded.0' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'folderAdded.1' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'folderAdded.2' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'import' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'link' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'logOut' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'myDevice' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'noFilesFound' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'noInternetConnection' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'pause' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'pauseUpload' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'paused' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'preparingUpload' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'processingXFiles.0' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'processingXFiles.1' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'processingXFiles.2' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'removeFile' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'resetFilter' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'resume' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'resumeUpload' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'retry' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'retryUpload' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'saveChanges' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'selectXFiles.0' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'selectXFiles.1' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'selectXFiles.2' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'smile' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'startRecording' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'stopRecording' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'takePicture' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'timedOut' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'uploadComplete' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'uploadFailed' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'uploadPaused' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'uploadXFiles.0' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'uploadXFiles.1' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'uploadXFiles.2' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'uploadXNewFiles.0' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'uploadXNewFiles.1' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'uploadXNewFiles.2' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'uploading' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'uploadingXFiles.0' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'uploadingXFiles.1' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'uploadingXFiles.2' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'xFilesSelected.0' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'xFilesSelected.1' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'xFilesSelected.2' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'xMoreFilesAdded.0' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'xMoreFilesAdded.1' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'xMoreFilesAdded.2' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'xTimeLeft' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'youCanOnlyUploadFileTypes' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'youCanOnlyUploadX.0' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'youCanOnlyUploadX.1' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'youCanOnlyUploadX.2' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'youHaveToAtLeastSelectX.0' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'youHaveToAtLeastSelectX.1' that is present in en_US. 
+- [ ] nb_NO locale has missing string: 'youHaveToAtLeastSelectX.2' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'addMoreFiles' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'addingMoreFiles' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'allowAccessDescription' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'allowAccessTitle' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'back' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'cancel' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'cancelUpload' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'chooseFiles' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'companionAuthError' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'companionError' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'complete' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'connectedToInternet' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'copyLink' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'creatingAssembly' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'creatingAssemblyFailed' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'dataUploadedOfTotal' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'dropHereOr' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'edit' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'editFile' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'editing' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'emptyFolderAdded' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'encoding' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'enterCorrectUrl' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'enterUrlToImport' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'exceedsSize' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'failedToFetch' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'failedToUpload' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'fileSource' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'filesUploadedOfTotal.0' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'filesUploadedOfTotal.1' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'filesUploadedOfTotal.2' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'filter' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'finishEditingFile' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'folderAdded.0' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'folderAdded.1' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'folderAdded.2' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'import' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'link' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'logOut' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'myDevice' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'noFilesFound' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'noInternetConnection' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'pause' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'pauseUpload' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'paused' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'preparingUpload' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'processingXFiles.0' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'processingXFiles.1' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'processingXFiles.2' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'removeFile' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'resetFilter' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'resume' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'resumeUpload' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'retry' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'retryUpload' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'saveChanges' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'selectXFiles.0' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'selectXFiles.1' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'selectXFiles.2' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'smile' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'startRecording' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'stopRecording' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'takePicture' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'timedOut' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'uploadComplete' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'uploadFailed' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'uploadPaused' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'uploadXFiles.0' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'uploadXFiles.1' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'uploadXFiles.2' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'uploadXNewFiles.0' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'uploadXNewFiles.1' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'uploadXNewFiles.2' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'uploading' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'uploadingXFiles.0' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'uploadingXFiles.1' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'uploadingXFiles.2' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'xFilesSelected.0' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'xFilesSelected.1' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'xFilesSelected.2' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'xMoreFilesAdded.0' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'xMoreFilesAdded.1' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'xMoreFilesAdded.2' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'xTimeLeft' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'youCanOnlyUploadFileTypes' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'youCanOnlyUploadX.0' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'youCanOnlyUploadX.1' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'youCanOnlyUploadX.2' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'youHaveToAtLeastSelectX.0' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'youHaveToAtLeastSelectX.1' that is present in en_US. 
+- [ ] pl_PL locale has missing string: 'youHaveToAtLeastSelectX.2' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'addMoreFiles' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'addingMoreFiles' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'allowAccessDescription' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'allowAccessTitle' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'back' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'browse' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'cancel' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'cancelUpload' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'chooseFiles' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'companionAuthError' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'companionError' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'complete' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'connectedToInternet' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'copyLink' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'creatingAssembly' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'creatingAssemblyFailed' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'dataUploadedOfTotal' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'dropHereOr' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'dropPaste' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'edit' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'editFile' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'editing' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'emptyFolderAdded' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'encoding' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'enterCorrectUrl' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'enterUrlToImport' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'exceedsSize' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'failedToFetch' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'failedToUpload' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'fileSource' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'filesUploadedOfTotal.0' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'filesUploadedOfTotal.1' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'filesUploadedOfTotal.2' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'filter' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'finishEditingFile' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'folderAdded.0' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'folderAdded.1' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'folderAdded.2' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'import' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'link' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'logOut' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'myDevice' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'noFilesFound' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'noInternetConnection' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'pause' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'pauseUpload' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'paused' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'preparingUpload' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'processingXFiles.0' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'processingXFiles.1' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'processingXFiles.2' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'removeFile' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'resetFilter' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'resume' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'resumeUpload' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'retry' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'retryUpload' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'saveChanges' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'selectXFiles.0' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'selectXFiles.1' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'selectXFiles.2' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'smile' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'startRecording' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'stopRecording' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'takePicture' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'timedOut' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'uploadComplete' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'uploadFailed' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'uploadPaused' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'uploadXFiles.0' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'uploadXFiles.1' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'uploadXFiles.2' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'uploadXNewFiles.0' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'uploadXNewFiles.1' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'uploadXNewFiles.2' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'uploading' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'uploadingXFiles.0' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'uploadingXFiles.1' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'uploadingXFiles.2' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'xFilesSelected.0' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'xFilesSelected.1' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'xFilesSelected.2' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'xMoreFilesAdded.0' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'xMoreFilesAdded.1' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'xMoreFilesAdded.2' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'xTimeLeft' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'youCanOnlyUploadFileTypes' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'youCanOnlyUploadX.0' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'youCanOnlyUploadX.1' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'youCanOnlyUploadX.2' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'youHaveToAtLeastSelectX.0' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'youHaveToAtLeastSelectX.1' that is present in en_US. 
+- [ ] pt_BR locale has missing string: 'youHaveToAtLeastSelectX.2' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'addMoreFiles' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'addingMoreFiles' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'allowAccessDescription' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'allowAccessTitle' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'back' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'cancel' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'cancelUpload' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'chooseFiles' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'companionAuthError' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'companionError' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'complete' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'connectedToInternet' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'copyLink' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'creatingAssembly' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'creatingAssemblyFailed' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'dataUploadedOfTotal' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'dropHereOr' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'edit' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'editFile' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'editing' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'emptyFolderAdded' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'encoding' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'enterCorrectUrl' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'enterUrlToImport' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'exceedsSize' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'failedToFetch' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'failedToUpload' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'fileSource' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'filesUploadedOfTotal.0' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'filesUploadedOfTotal.1' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'filesUploadedOfTotal.2' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'filter' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'finishEditingFile' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'folderAdded.0' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'folderAdded.1' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'folderAdded.2' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'import' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'link' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'logOut' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'myDevice' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'noFilesFound' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'noInternetConnection' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'pause' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'pauseUpload' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'paused' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'preparingUpload' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'processingXFiles.0' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'processingXFiles.1' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'processingXFiles.2' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'removeFile' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'resetFilter' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'resume' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'resumeUpload' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'retry' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'retryUpload' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'saveChanges' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'selectXFiles.0' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'selectXFiles.1' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'selectXFiles.2' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'smile' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'startRecording' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'stopRecording' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'takePicture' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'timedOut' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'uploadComplete' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'uploadFailed' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'uploadPaused' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'uploadXFiles.0' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'uploadXFiles.1' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'uploadXFiles.2' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'uploadXNewFiles.0' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'uploadXNewFiles.1' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'uploadXNewFiles.2' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'uploading' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'uploadingXFiles.0' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'uploadingXFiles.1' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'uploadingXFiles.2' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'xFilesSelected.0' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'xFilesSelected.1' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'xFilesSelected.2' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'xMoreFilesAdded.0' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'xMoreFilesAdded.1' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'xMoreFilesAdded.2' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'xTimeLeft' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'youCanOnlyUploadFileTypes' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'youCanOnlyUploadX.0' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'youCanOnlyUploadX.1' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'youCanOnlyUploadX.2' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'youHaveToAtLeastSelectX.0' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'youHaveToAtLeastSelectX.1' that is present in en_US. 
+- [ ] tr_TR locale has missing string: 'youHaveToAtLeastSelectX.2' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'addMoreFiles' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'addingMoreFiles' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'allowAccessDescription' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'allowAccessTitle' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'back' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'browse' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'cancel' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'cancelUpload' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'chooseFiles' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'companionAuthError' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'companionError' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'complete' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'connectedToInternet' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'copyLink' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'copyLinkToClipboardFallback' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'copyLinkToClipboardSuccess' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'creatingAssembly' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'creatingAssemblyFailed' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'dashboardTitle' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'dashboardWindowTitle' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'dataUploadedOfTotal' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'done' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'dropHereOr' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'dropPaste' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'dropPasteImport' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'edit' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'editFile' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'editing' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'emptyFolderAdded' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'encoding' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'enterCorrectUrl' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'enterUrlToImport' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'exceedsSize' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'failedToFetch' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'failedToUpload' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'fileSource' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'filesUploadedOfTotal.0' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'filesUploadedOfTotal.1' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'filesUploadedOfTotal.2' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'filter' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'finishEditingFile' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'folderAdded.0' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'folderAdded.1' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'folderAdded.2' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'import' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'importFrom' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'link' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'logOut' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'myDevice' that is present in en_US. 
+- [ ] zh_CN locale has missing string: 'noFilesFound' that is present in en_US. 

+ 63 - 0
packages/@uppy/locales/legacy/cs_CZ.js

@@ -0,0 +1,63 @@
+/* eslint camelcase: 0 */
+
+const cs_CZ = {}
+
+cs_CZ.strings = {
+  chooseFile: 'Vyberte soubor',
+  orDragDrop: 'nebo ho sem přetáhněte',
+  youHaveChosen: 'Vybrali jste: %{fileName}',
+  filesChosen: {
+    0: '%{smart_count} soubor vybrán',
+    1: '%{smart_count} soubory vybrány',
+    2: '%{smart_count} souborů vybráno'
+  },
+  filesUploaded: {
+    0: '%{smart_count} soubor nahrán',
+    1: '%{smart_count} soubory nahrány',
+    2: '%{smart_count} souborů nahráno'
+  },
+  files: {
+    0: '%{smart_count} soubor',
+    1: '%{smart_count} soubory',
+    2: '%{smart_count} souborů'
+  },
+  uploadFiles: {
+    0: 'Nahrát %{smart_count} soubor',
+    1: 'Nahrát %{smart_count} soubory',
+    2: 'Nahrát %{smart_count} souborů'
+  },
+  selectToUpload: 'Vybrat soubory k nahrání',
+  closeModal: 'Zavřít okno',
+  upload: 'Nahrát',
+  importFrom: 'Importovat soubory z',
+  dashboardWindowTitle: 'Uppy Dashboard okno (Pro zavření stiskněte Escape)',
+  dashboardTitle: 'Uppy Dashboard',
+  copyLinkToClipboardSuccess: 'Odkaz zkopírován do schránky.',
+  copyLinkToClipboardFallback: 'Zkopírovat následující odkaz',
+  done: 'Hotovo',
+  localDisk: 'Disk',
+  dropPasteImport: 'Přetáhněte soubory, vložte je, importujte je z některých výše uvedených služeb, nebo',
+  dropPaste: 'Přetáhněte soubory, vložte je, nebo',
+  browse: 'procházejte',
+  fileProgress: 'Nahrávání: rychlost nahrávání a zbývající čas',
+  numberOfSelectedFiles: 'Počet vybraných souborů',
+  uploadAllNewFiles: 'Nahrát všechny nové soubory'
+}
+
+cs_CZ.pluralize = function (n) {
+  if (n === 1) {
+    return 0
+  }
+
+  if (n >= 2 && n <= 4) {
+    return 1
+  }
+
+  return 2
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.cs_CZ = cs_CZ
+}
+
+module.exports = cs_CZ

+ 54 - 0
packages/@uppy/locales/legacy/de_DE.js

@@ -0,0 +1,54 @@
+/* eslint camelcase: 0 */
+
+const de_DE = {}
+
+de_DE.strings = {
+  chooseFile: 'Wähle eine Datei',
+  youHaveChosen: 'Du hast gewählt: %{fileName}',
+  orDragDrop: 'oder schiebe Sie hier her',
+  filesChosen: {
+    0: '%{smart_count} Datei gewählt',
+    1: '%{smart_count} Dateien gewählt'
+  },
+  filesUploaded: {
+    0: '%{smart_count} Datei hochgeladen',
+    1: '%{smart_count} Dateien hochgeladen'
+  },
+  files: {
+    0: '%{smart_count} Datei',
+    1: '%{smart_count} Dateien'
+  },
+  uploadFiles: {
+    0: 'Upload %{smart_count} Datei',
+    1: 'Upload %{smart_count} Dateien'
+  },
+  selectToUpload: 'Ausgewählten Dateien wurden hochgeladen',
+  closeModal: 'Schließen Modal',
+  upload: 'Hochladen',
+  importFrom: 'Importiere Daten von',
+  dashboardWindowTitle: 'Uppy Dashboard Fenster (Drücke Escape zum schließen)',
+  dashboardTitle: 'Uppy Dashboard',
+  copyLinkToClipboardSuccess: 'Link wurde in Zwischenablage kopiert.',
+  copyLinkToClipboardFallback: 'Kopiere die untere URL',
+  done: 'Fertig',
+  localDisk: 'Lokale Festplatte',
+  dropPasteImport: 'Ziehe Dateien hier her, einfügen, importieren aus einer der oberen Quellen oder',
+  dropPaste: 'Zihe Dateien hier her, einfügen oder',
+  browse: 'Durchsuchen',
+  fileProgress: 'Datei Fortschritt: Upload Geschwindigkeit und ETA',
+  numberOfSelectedFiles: 'Anzahl gewählter Dateien',
+  uploadAllNewFiles: 'Alle neuen Dateien hochladen'
+}
+
+de_DE.pluralize = function (n) {
+  if (n === 1) {
+    return 0
+  }
+  return 1
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.de_DE = de_DE
+}
+
+module.exports = de_DE

+ 54 - 0
packages/@uppy/locales/legacy/es_ES.js

@@ -0,0 +1,54 @@
+/* eslint camelcase: 0 */
+
+const es_ES = {}
+
+es_ES.strings = {
+  chooseFile: 'Selecciona un fichero',
+  youHaveChosen: 'Has seleccionado: %{fileName}',
+  orDragDrop: 'o arrástralo aquí',
+  filesChosen: {
+    0: '%{smart_count} fichero seleccionado',
+    1: '%{smart_count} ficheros seleccionados'
+  },
+  filesUploaded: {
+    0: '%{smart_count} fichero subido',
+    1: '%{smart_count} ficheros subidos'
+  },
+  files: {
+    0: '%{smart_count} fichero',
+    1: '%{smart_count} ficheros'
+  },
+  uploadFiles: {
+    0: 'Subir %{smart_count} fichero',
+    1: 'Subir %{smart_count} ficheros'
+  },
+  selectToUpload: 'Selecciona los ficheros a subir',
+  closeModal: 'Cerrar modal',
+  upload: 'Subir',
+  importFrom: 'Importar ficheros desde',
+  dashboardWindowTitle: 'Panel de Uppy (Pulsa escape para cerrar)',
+  dashboardTitle: 'Panel de Uppy',
+  copyLinkToClipboardSuccess: 'Enlace copiado al portapapeles.',
+  copyLinkToClipboardFallback: 'Copiar la siguiente URL',
+  done: 'Hecho',
+  localDisk: 'Disco local',
+  dropPasteImport: 'Arrasta ficheros aquí, pega, importa de alguno de los servicios de arriba o',
+  dropPaste: 'Arrastra ficheros aquí, pega o',
+  browse: 'navegar',
+  fileProgress: 'Progreso: velocidad de subida y tiempo estimado',
+  numberOfSelectedFiles: 'Número de ficheros seleccionados',
+  uploadAllNewFiles: 'Subir todos los nuevos ficheros'
+}
+
+es_ES.pluralize = function (n) {
+  if (n === 1) {
+    return 0
+  }
+  return 1
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.es_ES = es_ES
+}
+
+module.exports = es_ES

+ 54 - 0
packages/@uppy/locales/legacy/fi_FI.js

@@ -0,0 +1,54 @@
+/* eslint camelcase: 0 */
+
+const fi_FI = {}
+
+fi_FI.strings = {
+  chooseFile: 'Valitse tiedosto',
+  youHaveChosen: 'Valitsit: %{fileName}',
+  orDragDrop: 'tai raahaa se tähän',
+  filesChosen: {
+    0: '%{smart_count} tiedosto valittu',
+    1: '%{smart_count} tiedostoa valittu'
+  },
+  filesUploaded: {
+    0: '%{smart_count} tiedosto siirretty',
+    1: '%{smart_count} tiedostoa siirretty'
+  },
+  files: {
+    0: '%{smart_count} tiedosto',
+    1: '%{smart_count} tiedostoa'
+  },
+  uploadFiles: {
+    0: 'Siirrä %{smart_count} tiedosto',
+    1: 'Siirrä %{smart_count} tiedostoa'
+  },
+  selectToUpload: 'Valitse siirrettävät tiedostot',
+  closeModal: 'Sulje ikkuna',
+  upload: 'Siirrä',
+  importFrom: 'Tuo tiedostoja',
+  dashboardWindowTitle: 'Uppy-ohjausnäkymä (Sulje Esc-näppäimellä)',
+  dashboardTitle: 'Uppy-ohjausnäkymä',
+  copyLinkToClipboardSuccess: 'Linkki kopioitu leikepöydälle.',
+  copyLinkToClipboardFallback: 'Kopioi allaoleva linkki',
+  done: 'Valmis',
+  localDisk: 'Paikallinen levy',
+  dropPasteImport: 'Pudota tiedosto(t) tähän, liitä, tuo tiedostoja ylläolevista sijainneista tai',
+  dropPaste: 'Pudota tiedosto(t) tähän, liitä tai',
+  browse: 'selaa',
+  fileProgress: 'Siirron edistyminen: lähetysnopeus ja arvioitu valmistumisaika',
+  numberOfSelectedFiles: 'Valittujen tiedostojen lukumäärä',
+  uploadAllNewFiles: 'Siirrä kaikki uudet tiedostot'
+}
+
+fi_FI.pluralize = function (n) {
+  if (n === 1) {
+    return 0
+  }
+  return 1
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.fi_FI = fi_FI
+}
+
+module.exports = fi_FI

+ 54 - 0
packages/@uppy/locales/legacy/id_ID.js

@@ -0,0 +1,54 @@
+/* eslint camelcase: 0 */
+
+const id_ID = {}
+
+id_ID.strings = {
+  chooseFile: 'Pilih berkas',
+  youHaveChosen: 'Berkas yang dipilih: %{fileName}',
+  orDragDrop: 'atau tarik dan taruh berkas ke sini',
+  filesChosen: {
+    0: '%{smart_count} berkas dipilih',
+    1: '%{smart_count} berkas dipilih'
+  },
+  filesUploaded: {
+    0: '%{smart_count} berkas terunggah',
+    1: '%{smart_count} berkas terunggah'
+  },
+  files: {
+    0: '%{smart_count} berkas',
+    1: '%{smart_count} berkas'
+  },
+  uploadFiles: {
+    0: 'Unggah %{smart_count} berkas',
+    1: 'Unggah %{smart_count} berkas'
+  },
+  selectToUpload: 'Pilih berkas untuk mengunggah',
+  closeModal: 'Tutup Modal',
+  upload: 'Unggah',
+  importFrom: 'Import berkas dari',
+  dashboardWindowTitle: 'Uppy Beranda Window (Tekan escape untuk menutup)',
+  dashboardTitle: 'Beranda Uppy',
+  copyLinkToClipboardSuccess: 'Link tersalin.',
+  copyLinkToClipboardFallback: 'Salin URL di bawah ini',
+  done: 'Selesai',
+  localDisk: 'Penyimpanan Lokal',
+  dropPasteImport: 'Taruh berkas di sini, tempel, import dari salah satu lokasi di atas atau',
+  dropPaste: 'Taruh berkas di sini, tempel atau',
+  browse: 'cari',
+  fileProgress: 'Proses berkas: kecepatan unggah dan ETA',
+  numberOfSelectedFiles: 'Total berkas yang di pilih',
+  uploadAllNewFiles: 'Unggah semua berkas baru'
+}
+
+id_ID.pluralize = function (n) {
+  if (n === 1) {
+    return 0
+  }
+  return 1
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.id_ID = id_ID
+}
+
+module.exports = id_ID

+ 54 - 0
packages/@uppy/locales/legacy/it_IT.js

@@ -0,0 +1,54 @@
+/* eslint camelcase: 0 */
+
+const it_IT = {}
+
+it_IT.strings = {
+  chooseFile: 'Seleziona un file',
+  youHaveChosen: 'Hai scelto: %{fileName}',
+  orDragDrop: 'oppure trascinalo qui',
+  filesChosen: {
+    0: '%{smart_count} file selezionato',
+    1: '%{smart_count} file selezionati'
+  },
+  filesUploaded: {
+    0: '%{smart_count} file caricato',
+    1: '%{smart_count} file caricati'
+  },
+  files: {
+    0: '%{smart_count} file',
+    1: '%{smart_count} file'
+  },
+  uploadFiles: {
+    0: 'Carica %{smart_count} file',
+    1: 'Carica %{smart_count} file'
+  },
+  selectToUpload: 'Seleziona i file da caricare',
+  closeModal: 'Chiudi la finestra',
+  upload: 'Carica',
+  importFrom: 'Importa i file da',
+  dashboardWindowTitle: 'Uppy Dashboard Window (Premi escape per chiuderla)',
+  dashboardTitle: 'Uppy Dashboard',
+  copyLinkToClipboardSuccess: 'Collegamento copiato negli appunti.',
+  copyLinkToClipboardFallback: 'Copia il seguente indirizzo',
+  done: 'Fatto',
+  localDisk: 'Disco locale',
+  dropPasteImport: 'Trascina i file qui, incolla, importa da uno dei servizi sopra oppure',
+  dropPaste: 'Trascina i file qui, incolla oppure',
+  browse: 'sfoglia',
+  fileProgress: 'Avanzamento del file: velocità di caricamento e tempo rimanente',
+  numberOfSelectedFiles: 'Numero di file selezionati',
+  uploadAllNewFiles: 'Carica tutti i nuovi file'
+}
+
+it_IT.pluralize = function (n) {
+  if (n === 1) {
+    return 0
+  }
+  return 1
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.it_IT = it_IT
+}
+
+module.exports = it_IT

+ 54 - 0
packages/@uppy/locales/legacy/nb_NO.js

@@ -0,0 +1,54 @@
+/* eslint camelcase: 0 */
+
+const nb_NO = {}
+
+nb_NO.strings = {
+  chooseFile: 'Velg en fil',
+  youHaveChosen: 'Du har valgt: %{fileName}',
+  orDragDrop: 'eller slipp den her',
+  filesChosen: {
+    0: '%{smart_count} fil valgt',
+    1: '%{smart_count} filer valgt'
+  },
+  filesUploaded: {
+    0: '%{smart_count} fil lastet opp',
+    1: '%{smart_count} filer lastet opp'
+  },
+  files: {
+    0: '%{smart_count} fil',
+    1: '%{smart_count} filer'
+  },
+  uploadFiles: {
+    0: 'Lastet opp %{smart_count} fil',
+    1: 'Lastet opp %{smart_count} filer'
+  },
+  selectToUpload: 'Velg filer å laste opp',
+  closeModal: 'Lukk dialogboksen',
+  upload: 'Last opp',
+  importFrom: 'Importer filer fra',
+  dashboardWindowTitle: 'Uppy Dashboard-vindu (Trykk escape for å lukke)',
+  dashboardTitle: 'Uppy Dashboard',
+  copyLinkToClipboardSuccess: 'Lenken ble kopiert til utklippstavla.',
+  copyLinkToClipboardFallback: 'Kopier URL-en under',
+  done: 'Ferdig',
+  localDisk: 'Lokal disk',
+  dropPasteImport: 'Du kan slippe eller lime inn filer her, importere fra en en av plasseringene ovenfor eller',
+  dropPaste: 'Du kan slippe eller lime inn filer her eller',
+  browse: 'velge dem',
+  fileProgress: 'Filstatus: Opplastingshastighet og ETA',
+  numberOfSelectedFiles: 'Antall valgte filer',
+  uploadAllNewFiles: 'Last opp alle nye filer'
+}
+
+nb_NO.pluralize = function (n) {
+  if (n === 1) {
+    return 0
+  }
+  return 1
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.nb_NO = nb_NO
+}
+
+module.exports = nb_NO

+ 61 - 0
packages/@uppy/locales/legacy/pl_PL.js

@@ -0,0 +1,61 @@
+/* eslint camelcase: 0 */
+
+const pl_PL = {}
+
+pl_PL.strings = {
+  chooseFile: 'Wybierz plik',
+  youHaveChosen: 'Wybrałeś: %{fileName}',
+  orDragDrop: 'lub przeciągnij tutaj',
+  filesChosen: {
+    0: '%{smart_count} wybrany plik',
+    1: '%{smart_count} wybrane pliki',
+    2: '%{smart_count} wybranych plików'
+  },
+  filesUploaded: {
+    0: '%{smart_count} wysłany plik',
+    1: '%{smart_count} wysłane pliki',
+    2: '%{smart_count} wysłanych plików'
+  },
+  files: {
+    0: '%{smart_count} plik',
+    1: '%{smart_count} pliki',
+    2: '%{smart_count} plików'
+  },
+  uploadFiles: {
+    0: 'Wyślij %{smart_count} plik',
+    1: 'Wyślij %{smart_count} pliki',
+    2: 'Wyślij %{smart_count} plików'
+  },
+  selectToUpload: 'Wybierz pliki do wysłania',
+  closeModal: 'Zamknij okno',
+  upload: 'Wyślij',
+  importFrom: 'Zaimportuj pliki z',
+  dashboardWindowTitle: 'Okno Uppy Dashboard (Wciśnij esc, aby zamknąć)',
+  dashboardTitle: 'Uppy Dashboard',
+  copyLinkToClipboardSuccess: 'Link skopiowany do schowka.',
+  copyLinkToClipboardFallback: 'Skopiuj poniższy link',
+  done: 'Gotowe',
+  localDisk: 'Dysk lokalny',
+  dropPasteImport: 'Upuść, wklej lub zaimportuj pliki tutaj albo',
+  dropPaste: 'Upuść lub wklej pliki tutaj albo',
+  browse: 'przeglądaj',
+  fileProgress: 'Postęp pliku: prędkość wysyłania i przewidywany pozostały czas',
+  numberOfSelectedFiles: 'Ilość wybranych plików',
+  uploadAllNewFiles: 'Wyślij wszystkie nowe pliki'
+}
+
+pl_PL.pluralize = function (n) {
+  if (n === 1) {
+    return 0
+  }
+  if (n >= 2 && n <= 4) {
+    return 1
+  }
+  return 2
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.pl_PL = pl_PL
+}
+
+module.exports = pl_PL

+ 52 - 0
packages/@uppy/locales/legacy/pt_BR.js

@@ -0,0 +1,52 @@
+/* eslint camelcase: 0 */
+
+const pt_BR = {}
+
+pt_BR.strings = {
+  chooseFile: 'Escolha um arquivo',
+  youHaveChosen: 'Você escolheu: %{fileName}',
+  orDragDrop: 'ou arraste-o aqui',
+  filesChosen: {
+    0: '%{smart_count} arquivo selecionado',
+    1: '%{smart_count} arquivos selecionados'
+  },
+  filesUploaded: {
+    0: '%{smart_count} arquivo enviado',
+    1: '%{smart_count} arquivos enviados'
+  },
+  files: {
+    0: '%{smart_count} arquivo',
+    1: '%{smart_count} arquivos'
+  },
+  uploadFiles: {
+    0: 'Enviar %{smart_count} arquivo',
+    1: 'Enviar %{smart_count} arquivos'
+  },
+  selectToUpload: 'Selecione arquivos para enviar',
+  closeModal: 'Fechar Modal',
+  upload: 'Enviar',
+  importFrom: 'Importar arquivos de',
+  dashboardWindowTitle: 'Painel do Uppy (Aperte Esc para fechar)',
+  dashboardTitle: 'Painel do Uppy',
+  copyLinkToClipboardSuccess: 'Link copiado para área de transferência.',
+  copyLinkToClipboardFallback: 'Copie a URL abaixo',
+  done: 'Finalizado',
+  localDisk: 'Disco Local',
+  dropPasteImport: 'Arraste arquivos até aqui, cole-os ou importe de:',
+  fileProgress: 'Progresso de Arquivo: velocidade de envio e estimativas',
+  numberOfSelectedFiles: 'Números de arquivos selecionados',
+  uploadAllNewFiles: 'Enviar todos os arquivos novos'
+}
+
+pt_BR.pluralize = function (n) {
+  if (n === 1) {
+    return 0
+  }
+  return 1
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.pt_BR = pt_BR
+}
+
+module.exports = pt_BR

+ 54 - 0
packages/@uppy/locales/legacy/tr_TR.js

@@ -0,0 +1,54 @@
+/* eslint camelcase: 0 */
+
+const tr_TR = {}
+
+tr_TR.strings = {
+  chooseFile: 'Dosya Seçin',
+  youHaveChosen: 'Seçmiş olduğun dosya: %{fileName}',
+  orDragDrop: 'yada bırakın',
+  filesChosen: {
+    0: '%{smart_count} adet dosya seçili',
+    1: '%{smart_count} adet dosyalar seçili'
+  },
+  filesUploaded: {
+    0: '%{smart_count} adet dosya yüklendi',
+    1: '%{smart_count} adet dosyalar yüklendi'
+  },
+  files: {
+    0: '%{smart_count} dosya',
+    1: '%{smart_count} dosyalar'
+  },
+  uploadFiles: {
+    0: 'Yüklenen %{smart_count} dosya',
+    1: 'Yüklenen %{smart_count} dosyalar'
+  },
+  selectToUpload: 'Yüklemek için dosyaları seçin',
+  closeModal: 'Pencereyi Kapat',
+  upload: 'Yükle',
+  importFrom: 'Dosyaları içeri aktar',
+  dashboardWindowTitle: 'Uppy Panel Pencerisi (kapatmak için esc kullanın)',
+  dashboardTitle: 'Uppy Panel',
+  copyLinkToClipboardSuccess: 'Bağlantı kopyalandı.',
+  copyLinkToClipboardFallback: 'Bağlantıyı kopyala.',
+  done: 'Bitti',
+  localDisk: 'Lokal Dosyalar',
+  dropPasteImport: 'Dosyaları buraya bırakın, yukarıdaki konumlardan birinden yapıştırın, içeri aktarın veya',
+  dropPaste: 'Dosyaları buraya bırak, yapıştır veya',
+  browse: 'Gözat',
+  fileProgress: 'Dosya ilerlemesi: yükleme hızı ve süresi',
+  numberOfSelectedFiles: 'Seçilen dosya sayısı',
+  uploadAllNewFiles: 'Tüm yeni dosyaları yükle'
+}
+
+tr_TR.pluralize = function (n) {
+  if (n === 1) {
+    return 0
+  }
+  return 1
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.tr_TR = tr_TR
+}
+
+module.exports = tr_TR

+ 34 - 0
packages/@uppy/locales/legacy/zh_CN.js

@@ -0,0 +1,34 @@
+/* eslint camelcase: 0 */
+
+const zh_CN = {}
+
+zh_CN.strings = {
+  chooseFile: '选择文件',
+  youHaveChosen: '你已经选择了: %{fileName}',
+  orDragDrop: '或者拖到这里来',
+  filesChosen: {
+    0: '已选 %{smart_count} 个文件'
+  },
+  filesUploaded: {
+    0: '已上传 %{smart_count} 个文件'
+  },
+  files: {
+    0: '%{smart_count} 个文件'
+  },
+  uploadFiles: {
+    0: '上传 %{smart_count} 个文件'
+  },
+  selectToUpload: '选择文件以上传',
+  closeModal: '关闭对话框',
+  upload: '上传'
+}
+
+zh_CN.pluralize = function (n) {
+  return 0
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.zh_CN = zh_CN
+}
+
+module.exports = zh_CN

+ 19 - 0
packages/@uppy/locales/package.json

@@ -0,0 +1,19 @@
+{
+  "name": "@uppy/locales",
+  "description": "",
+  "version": "0.30.4",
+  "license": "MIT",
+  "keywords": [
+    "uppy",
+    "uppy-plugin",
+    "language packs"
+  ],
+  "homepage": "https://uppy.io",
+  "bugs": {
+    "url": "https://github.com/transloadit/uppy/issues"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/transloadit/uppy.git"
+  }
+}

+ 143 - 0
packages/@uppy/locales/src/en_US.js

@@ -0,0 +1,143 @@
+/* eslint camelcase: 0 */
+
+const en_US = {}
+
+en_US.strings = {
+  addMoreFiles: 'Add more files',
+  addingMoreFiles: 'Adding more files',
+  allowAccessDescription: 'In order to take pictures or record video with your camera, please allow camera access for this site.',
+  allowAccessTitle: 'Please allow access to your camera',
+  back: 'Back',
+  browse: 'browse',
+  cancel: 'Cancel',
+  cancelUpload: 'Cancel upload',
+  chooseFiles: 'Choose files',
+  closeModal: 'Close Modal',
+  companionAuthError: 'Authorization required',
+  companionError: 'Connection with Companion failed',
+  complete: 'Complete',
+  connectedToInternet: 'Connected to the Internet',
+  copyLink: 'Copy link',
+  copyLinkToClipboardFallback: 'Copy the URL below',
+  copyLinkToClipboardSuccess: 'Link copied to clipboard',
+  creatingAssembly: 'Preparing upload...',
+  creatingAssemblyFailed: 'Transloadit: Could not create Assembly',
+  dashboardTitle: 'Uppy Dashboard',
+  dashboardWindowTitle: 'Uppy Dashboard Window (Press escape to close)',
+  dataUploadedOfTotal: '%{complete} of %{total}',
+  done: 'Done',
+  dropHereOr: 'Drop files here or %{browse}',
+  dropPaste: 'Drop files here, paste or %{browse}',
+  dropPasteImport: 'Drop files here, paste, %{browse} or import from',
+  edit: 'Edit',
+  editFile: 'Edit file',
+  editing: 'Editing %{file}',
+  emptyFolderAdded: 'No files were added from empty folder',
+  encoding: 'Encoding...',
+  enterCorrectUrl: 'Incorrect URL: Please make sure you are entering a direct link to a file',
+  enterUrlToImport: 'Enter URL to import a file',
+  exceedsSize: 'This file exceeds maximum allowed size of',
+  failedToFetch: 'Companion failed to fetch this URL, please make sure it’s correct',
+  failedToUpload: 'Failed to upload %{file}',
+  fileSource: 'File source: %{name}',
+  filesUploadedOfTotal: {
+    '0': '%{complete} of %{smart_count} file uploaded',
+    '1': '%{complete} of %{smart_count} files uploaded',
+    '2': '%{complete} of %{smart_count} files uploaded'
+  },
+  filter: 'Filter',
+  finishEditingFile: 'Finish editing file',
+  folderAdded: {
+    '0': 'Added %{smart_count} file from %{folder}',
+    '1': 'Added %{smart_count} files from %{folder}',
+    '2': 'Added %{smart_count} files from %{folder}'
+  },
+  import: 'Import',
+  importFrom: 'Import from %{name}',
+  link: 'Link',
+  logOut: 'Log out',
+  myDevice: 'My Device',
+  noFilesFound: 'You have no files or folders here',
+  noInternetConnection: 'No Internet connection',
+  pause: 'Pause',
+  pauseUpload: 'Pause upload',
+  paused: 'Paused',
+  preparingUpload: 'Preparing upload...',
+  processingXFiles: {
+    '0': 'Processing %{smart_count} file',
+    '1': 'Processing %{smart_count} files',
+    '2': 'Processing %{smart_count} files'
+  },
+  removeFile: 'Remove file',
+  resetFilter: 'Reset filter',
+  resume: 'Resume',
+  resumeUpload: 'Resume upload',
+  retry: 'Retry',
+  retryUpload: 'Retry upload',
+  saveChanges: 'Save changes',
+  selectXFiles: {
+    '0': 'Select %{smart_count} file',
+    '1': 'Select %{smart_count} files',
+    '2': 'Select %{smart_count} files'
+  },
+  smile: 'Smile!',
+  startRecording: 'Begin video recording',
+  stopRecording: 'Stop video recording',
+  takePicture: 'Take a picture',
+  timedOut: 'Upload stalled for %{seconds} seconds, aborting.',
+  upload: 'Upload',
+  uploadComplete: 'Upload complete',
+  uploadFailed: 'Upload failed',
+  uploadPaused: 'Upload paused',
+  uploadXFiles: {
+    '0': 'Upload %{smart_count} file',
+    '1': 'Upload %{smart_count} files',
+    '2': 'Upload %{smart_count} files'
+  },
+  uploadXNewFiles: {
+    '0': 'Upload +%{smart_count} file',
+    '1': 'Upload +%{smart_count} files',
+    '2': 'Upload +%{smart_count} files'
+  },
+  uploading: 'Uploading',
+  uploadingXFiles: {
+    '0': 'Uploading %{smart_count} file',
+    '1': 'Uploading %{smart_count} files',
+    '2': 'Uploading %{smart_count} files'
+  },
+  xFilesSelected: {
+    '0': '%{smart_count} file selected',
+    '1': '%{smart_count} files selected',
+    '2': '%{smart_count} files selected'
+  },
+  xMoreFilesAdded: {
+    '0': '%{smart_count} more file added',
+    '1': '%{smart_count} more files added',
+    '2': '%{smart_count} more files added'
+  },
+  xTimeLeft: '%{time} left',
+  youCanOnlyUploadFileTypes: 'You can only upload: %{types}',
+  youCanOnlyUploadX: {
+    '0': 'You can only upload %{smart_count} file',
+    '1': 'You can only upload %{smart_count} files',
+    '2': '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',
+    '2': 'You have to select at least %{smart_count} files'
+  }
+}
+
+en_US.pluralize = function (n) {
+  if (n === 1) {
+    return 0
+  }
+  return 1
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.en_US = en_US
+}
+
+module.exports = en_US

+ 148 - 0
packages/@uppy/locales/src/ru_RU.js

@@ -0,0 +1,148 @@
+/* eslint camelcase: 0 */
+
+const ru_RU = {}
+
+ru_RU.strings = {
+  addMoreFiles: 'Добавить дополнительные файлы',
+  addingMoreFiles: 'Добавление дополнительных файлов',
+  allowAccessDescription: 'Чтобы сделать фото или видео с помощью вашей камеры, пожалуйста разрешите доступ к камере для этого сайта',
+  allowAccessTitle: 'Пожалуйста, разрешите доступ к камере',
+  back: 'Назад',
+  browse: 'выберите',
+  cancel: 'Отмена',
+  cancelUpload: 'Отменить загрузку',
+  chooseFiles: 'Выбрать файлы',
+  closeModal: 'Закрыть окно',
+  companionAuthError: 'Требуется авторизация',
+  companionError: 'Connection with Companion failed',
+  complete: 'Готово',
+  connectedToInternet: 'Подключено к интернету',
+  copyLink: 'Скопировать ссылку',
+  copyLinkToClipboardFallback: 'Copy the URL below',
+  copyLinkToClipboardSuccess: 'Ссылка скопирована в буфер обмена',
+  creatingAssembly: 'Preparing upload...',
+  creatingAssemblyFailed: 'Transloadit: Could not create Assembly',
+  dashboardTitle: 'Uppy Dashboard',
+  dashboardWindowTitle: 'Uppy Dashboard Window (Press escape to close)',
+  dataUploadedOfTotal: '%{complete} of %{total}',
+  done: 'Готово',
+  dropHereOr: 'Перетащите файлы сюда или %{browse}',
+  dropPaste: 'Drop files here, paste or %{browse}',
+  dropPasteImport: 'Перенесите файлы сюда, вставьте, %{browse} или импортируйте',
+  edit: 'Редактировать',
+  editFile: 'Редактировать файл',
+  editing: 'Редактируется %{file}',
+  emptyFolderAdded: 'No files were added from empty folder',
+  encoding: 'Encoding...',
+  enterCorrectUrl: 'Incorrect URL: Please make sure you are entering a direct link to a file',
+  enterUrlToImport: 'Введите адрес URL, чтобы импортировать файл',
+  exceedsSize: 'This file exceeds maximum allowed size of',
+  failedToFetch: 'Companion failed to fetch this URL, please make sure it’s correct',
+  failedToUpload: 'Failed to upload %{file}',
+  fileSource: 'File source: %{name}',
+  filesUploadedOfTotal: {
+    '0': '%{complete} of %{smart_count} file uploaded',
+    '1': '%{complete} of %{smart_count} files uploaded',
+    '2': '%{complete} of %{smart_count} files uploaded'
+  },
+  filter: 'Фильтр',
+  finishEditingFile: 'Finish editing file',
+  folderAdded: {
+    '0': 'Added %{smart_count} file from %{folder}',
+    '1': 'Added %{smart_count} files from %{folder}',
+    '2': 'Added %{smart_count} files from %{folder}'
+  },
+  import: 'Импортировать',
+  importFrom: 'Импортировать из %{name}',
+  link: 'Ссылка',
+  logOut: 'Выйти',
+  myDevice: 'Мое устройство',
+  noFilesFound: 'You have no files or folders here',
+  noInternetConnection: 'Нет подключения к интернету',
+  pause: 'Поставить на паузу',
+  pauseUpload: 'Pause upload',
+  paused: 'На паузе',
+  preparingUpload: 'Приготовление к загрузке...',
+  processingXFiles: {
+    '0': 'Processing %{smart_count} file',
+    '1': 'Processing %{smart_count} files',
+    '2': 'Processing %{smart_count} files'
+  },
+  removeFile: 'Remove file',
+  resetFilter: 'Reset filter',
+  resume: 'Resume',
+  resumeUpload: 'Resume upload',
+  retry: 'Retry',
+  retryUpload: 'Retry upload',
+  saveChanges: 'Сохранить изменения',
+  selectXFiles: {
+    '0': 'Select %{smart_count} file',
+    '1': 'Select %{smart_count} files',
+    '2': 'Select %{smart_count} files'
+  },
+  smile: 'Smile!',
+  startRecording: 'Begin video recording',
+  stopRecording: 'Stop video recording',
+  takePicture: 'Take a picture',
+  timedOut: 'Upload stalled for %{seconds} seconds, aborting.',
+  upload: 'Upload',
+  uploadComplete: 'Upload complete',
+  uploadFailed: 'Upload failed',
+  uploadPaused: 'Upload paused',
+  uploadXFiles: {
+    '0': 'Upload %{smart_count} file',
+    '1': 'Upload %{smart_count} files',
+    '2': 'Upload %{smart_count} files'
+  },
+  uploadXNewFiles: {
+    '0': 'Upload +%{smart_count} file',
+    '1': 'Upload +%{smart_count} files',
+    '2': 'Upload +%{smart_count} files'
+  },
+  uploading: 'Uploading',
+  uploadingXFiles: {
+    '0': 'Uploading %{smart_count} file',
+    '1': 'Uploading %{smart_count} files',
+    '2': 'Uploading %{smart_count} files'
+  },
+  xFilesSelected: {
+    '0': '%{smart_count} file selected',
+    '1': '%{smart_count} files selected',
+    '2': '%{smart_count} files selected'
+  },
+  xMoreFilesAdded: {
+    '0': '%{smart_count} more file added',
+    '1': '%{smart_count} more files added',
+    '2': '%{smart_count} more files added'
+  },
+  xTimeLeft: '%{time} left',
+  youCanOnlyUploadFileTypes: 'You can only upload: %{types}',
+  youCanOnlyUploadX: {
+    '0': 'You can only upload %{smart_count} file',
+    '1': 'You can only upload %{smart_count} files',
+    '2': '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',
+    '2': 'You have to select at least %{smart_count} files'
+  }
+}
+
+ru_RU.pluralize = function (n) {
+  if (n % 10 === 1 && n % 100 !== 11) {
+    return 0
+  }
+
+  if (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20)) {
+    return 1
+  }
+
+  return 2
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.ru_RU = ru_RU
+}
+
+module.exports = ru_RU

+ 18 - 0
packages/@uppy/locales/template.js

@@ -0,0 +1,18 @@
+/* eslint camelcase: 0 */
+
+const en_US = {}
+
+en_US.strings = {}
+
+en_US.pluralize = function (n) {
+  if (n === 1) {
+    return 0
+  }
+  return 1
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.en_US = en_US
+}
+
+module.exports = en_US

+ 10 - 14
packages/@uppy/status-bar/src/index.js

@@ -16,41 +16,38 @@ module.exports = class StatusBar extends Plugin {
     this.title = 'StatusBar'
     this.type = 'progressindicator'
 
-    const defaultLocale = {
+    this.defaultLocale = {
       strings: {
         uploading: 'Uploading',
         upload: 'Upload',
         complete: 'Complete',
         uploadFailed: 'Upload failed',
-        pleasePressRetry: 'Please press Retry to upload again',
         paused: 'Paused',
-        error: 'Error',
         retry: 'Retry',
         cancel: 'Cancel',
         pause: 'Pause',
         resume: 'Resume',
-        pressToRetry: 'Press to retry',
-        // retryUpload: 'Retry upload',
-        // resumeUpload: 'Resume upload',
-        // cancelUpload: 'Cancel upload',
-        // pauseUpload: 'Pause upload',
         filesUploadedOfTotal: {
           0: '%{complete} of %{smart_count} file uploaded',
-          1: '%{complete} of %{smart_count} files uploaded'
+          1: '%{complete} of %{smart_count} files uploaded',
+          2: '%{complete} of %{smart_count} files uploaded'
         },
         dataUploadedOfTotal: '%{complete} of %{total}',
         xTimeLeft: '%{time} left',
         uploadXFiles: {
           0: 'Upload %{smart_count} file',
-          1: 'Upload %{smart_count} files'
+          1: 'Upload %{smart_count} files',
+          2: 'Upload %{smart_count} files'
         },
         uploadXNewFiles: {
           0: 'Upload +%{smart_count} file',
-          1: 'Upload +%{smart_count} files'
+          1: 'Upload +%{smart_count} files',
+          2: 'Upload +%{smart_count} files'
         },
         xMoreFilesAdded: {
           0: '%{smart_count} more file added',
-          1: '%{smart_count} more files added'
+          1: '%{smart_count} more files added',
+          2: '%{smart_count} more files added'
         }
       }
     }
@@ -63,14 +60,13 @@ module.exports = class StatusBar extends Plugin {
       hidePauseResumeButton: false,
       hideCancelButton: false,
       showProgressDetails: false,
-      locale: defaultLocale,
       hideAfterFinish: true
     }
 
     // merge default options with the ones set by user
     this.opts = Object.assign({}, defaultOptions, opts)
 
-    this.translator = new Translator([ defaultLocale, this.uppy.locale, this.opts.locale ])
+    this.translator = new Translator([ this.defaultLocale, this.uppy.locale, this.opts.locale ])
     this.i18n = this.translator.translate.bind(this.translator)
 
     this.startUpload = this.startUpload.bind(this)

+ 3 - 4
packages/@uppy/transloadit/src/index.js

@@ -31,7 +31,7 @@ module.exports = class Transloadit extends Plugin {
     this.id = 'Transloadit'
     this.title = 'Transloadit'
 
-    const defaultLocale = {
+    this.defaultLocale = {
       strings: {
         creatingAssembly: 'Preparing upload...',
         creatingAssemblyFailed: 'Transloadit: Could not create Assembly',
@@ -48,8 +48,7 @@ module.exports = class Transloadit extends Plugin {
       signature: null,
       params: null,
       fields: {},
-      getAssemblyOptions: defaultGetAssemblyOptions,
-      locale: defaultLocale
+      getAssemblyOptions: defaultGetAssemblyOptions
     }
 
     this.opts = {
@@ -58,7 +57,7 @@ module.exports = class Transloadit extends Plugin {
     }
 
     // i18n
-    this.translator = new Translator([ defaultLocale, this.uppy.locale, this.opts.locale ])
+    this.translator = new Translator([ this.defaultLocale, this.uppy.locale, this.opts.locale ])
     this.i18n = this.translator.translate.bind(this.translator)
     this.i18nArray = this.translator.translateArray.bind(this.translator)
 

+ 3 - 5
packages/@uppy/url/src/index.js

@@ -20,7 +20,7 @@ module.exports = class Url extends Plugin {
     </svg>
 
     // Set default options and locale
-    const defaultLocale = {
+    this.defaultLocale = {
       strings: {
         import: 'Import',
         enterUrlToImport: 'Enter URL to import a file',
@@ -29,14 +29,12 @@ module.exports = class Url extends Plugin {
       }
     }
 
-    const defaultOptions = {
-      locale: defaultLocale
-    }
+    const defaultOptions = {}
 
     this.opts = Object.assign({}, defaultOptions, opts)
 
     // i18n
-    this.translator = new Translator([ defaultLocale, this.uppy.locale, this.opts.locale ])
+    this.translator = new Translator([ this.defaultLocale, this.uppy.locale, this.opts.locale ])
     this.i18n = this.translator.translate.bind(this.translator)
     this.i18nArray = this.translator.translateArray.bind(this.translator)
 

+ 2 - 3
packages/@uppy/webcam/src/index.js

@@ -43,7 +43,7 @@ module.exports = class Webcam extends Plugin {
     this.type = 'acquirer'
     this.icon = CameraIcon
 
-    const defaultLocale = {
+    this.defaultLocale = {
       strings: {
         smile: 'Smile!',
         takePicture: 'Take a picture',
@@ -58,7 +58,6 @@ module.exports = class Webcam extends Plugin {
     const defaultOptions = {
       onBeforeSnapshot: () => Promise.resolve(),
       countdown: false,
-      locale: defaultLocale,
       modes: [
         'video-audio',
         'video-only',
@@ -73,7 +72,7 @@ module.exports = class Webcam extends Plugin {
     this.opts = Object.assign({}, defaultOptions, opts)
 
     // i18n
-    this.translator = new Translator([ defaultLocale, this.uppy.locale, this.opts.locale ])
+    this.translator = new Translator([ this.defaultLocale, this.uppy.locale, this.opts.locale ])
     this.i18n = this.translator.translate.bind(this.translator)
     this.i18nArray = this.translator.translateArray.bind(this.translator)
 

+ 2 - 3
packages/@uppy/xhr-upload/src/index.js

@@ -28,7 +28,7 @@ module.exports = class XHRUpload extends Plugin {
     this.id = 'XHRUpload'
     this.title = 'XHRUpload'
 
-    const defaultLocale = {
+    this.defaultLocale = {
       strings: {
         timedOut: 'Upload stalled for %{seconds} seconds, aborting.'
       }
@@ -43,7 +43,6 @@ module.exports = class XHRUpload extends Plugin {
       responseUrlFieldName: 'url',
       bundle: false,
       headers: {},
-      locale: defaultLocale,
       timeout: 30 * 1000,
       limit: 0,
       withCredentials: false,
@@ -90,7 +89,7 @@ module.exports = class XHRUpload extends Plugin {
     this.opts = Object.assign({}, defaultOptions, opts)
 
     // i18n
-    this.translator = new Translator([ defaultLocale, this.uppy.locale, this.opts.locale ])
+    this.translator = new Translator([ this.defaultLocale, this.uppy.locale, this.opts.locale ])
     this.i18n = this.translator.translate.bind(this.translator)
     this.i18nArray = this.translator.translateArray.bind(this.translator)
 

+ 2 - 0
packages/uppy/index.js

@@ -38,3 +38,5 @@ exports.Form = require('@uppy/form')
 exports.GoldenRetriever = require('@uppy/golden-retriever')
 exports.ReduxDevTools = require('@uppy/redux-dev-tools')
 exports.ThumbnailGenerator = require('@uppy/thumbnail-generator')
+
+exports.locales = {}

+ 4 - 1
website/inject.js

@@ -12,6 +12,7 @@ const touch = require('touch')
 const webRoot = __dirname
 const uppyRoot = path.join(__dirname, '../packages/uppy')
 const robodogRoot = path.join(__dirname, '../packages/@uppy/robodog')
+const localesRoot = path.join(__dirname, '../packages/@uppy/locales')
 
 const configPath = path.join(webRoot, '/themes/uppy/_config.yml')
 const { version } = require(path.join(uppyRoot, '/package.json'))
@@ -113,8 +114,10 @@ async function injectSizes (config) {
 async function injectBundles () {
   const cmds = [
     `mkdir -p ${path.join(webRoot, '/themes/uppy/source/uppy')}`,
+    `mkdir -p ${path.join(webRoot, '/themes/uppy/source/uppy/locales')}`,
     `cp -vfR ${path.join(uppyRoot, '/dist/*')} ${path.join(webRoot, '/themes/uppy/source/uppy/')}`,
-    `cp -vfR ${path.join(robodogRoot, '/dist/*')} ${path.join(webRoot, '/themes/uppy/source/uppy/')}`
+    `cp -vfR ${path.join(robodogRoot, '/dist/*')} ${path.join(webRoot, '/themes/uppy/source/uppy/')}`,
+    `cp -vfR ${path.join(localesRoot, '/dist/*')} ${path.join(webRoot, '/themes/uppy/source/uppy/locales')}`
   ].join(' && ')
 
   const { stdout } = await promisify(exec)(cmds)

+ 0 - 3
website/src/docs/statusbar.md

@@ -117,11 +117,8 @@ strings: {
   complete: 'Complete',
   // Shown in the status bar if an upload failed.
   uploadFailed: 'Upload failed',
-  // Shown next to `uploadFailed`.
-  pleasePressRetry: 'Please press Retry to upload again',
   // Shown in the status bar while the upload is paused.
   paused: 'Paused',
-  error: 'Error',
   // Used as the label for the button that retries an upload.
   retry: 'Retry',
   // Used as the label for the button that cancels an upload.

+ 15 - 1
website/src/docs/uppy.md

@@ -48,7 +48,7 @@ const uppy = Uppy({
   meta: {},
   onBeforeFileAdded: (currentFile, files) => currentFile,
   onBeforeUpload: (files) => {},
-  locale: defaultLocale,
+  locale: {},
   store: new DefaultStore()
 })
 ```
@@ -215,6 +215,19 @@ locale: {
 }
 ```
 
+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
+const russianLocale = require('@uppy/locales/lib/ru_RU')
+const uppy = 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 determine which string will be used for the provided `smart_count` number.
 
 For example, for the Icelandic language, the pluralization function would be:
@@ -227,6 +240,7 @@ locale: {
 
 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 simple object is used.

+ 28 - 1
website/src/docs/writing-plugins.md

@@ -192,4 +192,31 @@ class NumFiles extends Plugin {
 }
 ```
 
-[core.setfilestate]: /docs/uppy#uppy-setFileState-fileID-state
+## Locales
+
+For any user facing language that you use while writing your Plugin, please provide them as strings in the `defaultLocale` property like so:
+
+```js
+this.defaultLocale = {
+  strings: {
+    youCanOnlyUploadFileTypes: 'You can only upload: %{types}',
+    youCanOnlyUploadX: {
+      0: 'You can only upload %{smart_count} file',
+      1: 'You can only upload %{smart_count} files',
+      2: 'You can only upload %{smart_count} files'
+    }
+  }
+}
+```
+
+This allows them to be overridden by Locale Packs, or directly when users pass `locale: { strings: youCanOnlyUploadFileTypes: 'Something else completely about %{types}'} }`. For this to work, it's currently also required that you add:
+
+```js
+// i18n
+this.translator = new Translator([ this.defaultLocale, this.uppy.locale, this.opts.locale ])
+this.i18n = this.translator.translate.bind(this.translator)
+this.i18nArray = this.translator.translateArray.bind(this.translator) 
+// ^-- Only if you're using i18nArray, which allows you to pass in JSX Components as well.
+```
+
+[core.setfilestate]: /docs/uppy#uppy-setFileState-fileID-state

+ 9 - 3
website/src/examples/i18n/app.html

@@ -7,14 +7,20 @@ https://transloadit.edgly.net/releases/uppy/v0.30.4/uppy.min.css -->
 <!-- Load Uppy pre-built bundled version. You can use Transloadit's CDN, Edgly:
 https://transloadit.edgly.net/releases/uppy/v0.30.4/uppy.min.js -->
 <script src="/uppy/uppy.min.js"></script>
+<script src="/uppy/locales/ru_RU.min.js"></script>
 <script>
-  var uppy = Uppy.Core({ debug: true, autoProceed: true });
+  var uppy = Uppy.Core({ 
+    debug: true, 
+    autoProceed: true,
+    locale: Uppy.locales.ru_RU
+  });
   uppy.use(Uppy.DragDrop, {
     target: '.UppyDragDrop',
+    // We are using the ru_RU locale pack (set above in Uppy.Core options),
+    // but you can also override specific strings like so:
     locale: {
       strings: {
-        dropHereOr: 'Перенесите файлы сюда или %{browse}',
-        browse: 'выберите'
+        browse: 'выберите ;-)'
       }
     }
   });

+ 1 - 1
website/src/examples/i18n/index.ejs

@@ -1,5 +1,5 @@
 ---
-title: Bundle & i18n
+title: CDN & Locales
 layout: example
 type: examples
 category: 'Examples'