From 0105373ceea6918b0d33907c059f55dcabd31649 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ram=C3=B3n=20Souza?= <contato@ramonsouza.com>
Date: Thu, 11 Mar 2021 08:42:41 -0300
Subject: [PATCH] Applies changes needed to serve locale files as static
 content (#11234)

* moving locales folder to /public and applying changes needed to serve locales as static files

* better dev/prod check

* transifex pull script changes to match new locales directory + ignore locales with less than 100 lines

* fix local/prod locales path

* merge fallback messages

* applies new locale changes to legacy client

`bbb-html5.nginx` file content should also be changed to the following:

```
location /html5client/locales {
  alias /usr/share/meteor/bundle/programs/web.browser/app/locales;
}

location /html5client/compatibility {
  alias /usr/share/meteor/bundle/programs/web.browser/app/compatibility;
}

location /html5client/resources {
  alias /usr/share/meteor/bundle/programs/web.browser/app/resources;
}

location /html5client/svgs {
  alias /usr/share/meteor/bundle/programs/web.browser/app/svgs;
}

location /html5client/fonts {
  alias /usr/share/meteor/bundle/programs/web.browser/app/fonts;
}

location /html5client {
  # proxy_pass http://127.0.0.1:4100; # use for development
  proxy_pass http://poolhtml5servers; # use for production
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "Upgrade";
}
```
---
 bigbluebutton-html5/.gitignore                |  2 +
 .../imports/startup/client/intl.jsx           | 65 +++++++++++++++++--
 .../imports/startup/server/index.js           | 46 ++++++-------
 .../ui/components/legacy/component.jsx        | 58 +++++++++++++++--
 .../imports/ui/components/settings/service.js |  2 +-
 .../{private => public}/locales/ar.json       |  0
 .../{private => public}/locales/az.json       |  0
 .../{private => public}/locales/bg_BG.json    |  0
 .../{private => public}/locales/ca.json       |  0
 .../{private => public}/locales/cs_CZ.json    |  0
 .../{private => public}/locales/da.json       |  0
 .../{private => public}/locales/de.json       |  0
 .../{private => public}/locales/el_GR.json    |  0
 .../{private => public}/locales/en.json       |  0
 .../{private => public}/locales/eo.json       |  0
 .../{private => public}/locales/es.json       |  0
 .../{private => public}/locales/es_ES.json    |  0
 .../{private => public}/locales/es_MX.json    |  0
 .../{private => public}/locales/et.json       |  0
 .../{private => public}/locales/eu.json       |  0
 .../{private => public}/locales/fa_IR.json    |  0
 .../{private => public}/locales/fi.json       |  0
 .../{private => public}/locales/fr.json       |  0
 .../{private => public}/locales/gl.json       |  0
 .../{private => public}/locales/he.json       |  0
 .../{private => public}/locales/hi_IN.json    |  0
 .../{private => public}/locales/hr.json       |  0
 .../{private => public}/locales/hu_HU.json    |  0
 .../{private => public}/locales/hy.json       |  0
 .../{private => public}/locales/id.json       |  0
 .../{private => public}/locales/it_IT.json    |  0
 .../{private => public}/locales/ja.json       |  0
 .../{private => public}/locales/ka.json       |  0
 .../{private => public}/locales/kk.json       |  0
 .../{private => public}/locales/km.json       |  0
 .../{private => public}/locales/kn.json       |  0
 .../{private => public}/locales/ko_KR.json    |  0
 .../{private => public}/locales/lo_LA.json    |  0
 .../{private => public}/locales/lt_LT.json    |  0
 .../{private => public}/locales/lv.json       |  0
 .../{private => public}/locales/mn_MN.json    |  0
 .../{private => public}/locales/nb_NO.json    |  0
 .../{private => public}/locales/nl.json       |  0
 .../{private => public}/locales/oc.json       |  0
 .../{private => public}/locales/pl_PL.json    |  0
 .../{private => public}/locales/pt.json       |  0
 .../{private => public}/locales/pt_BR.json    |  0
 .../{private => public}/locales/ro_RO.json    |  0
 .../{private => public}/locales/ru.json       |  0
 .../{private => public}/locales/ru_RU.json    |  0
 .../{private => public}/locales/sk_SK.json    |  0
 .../{private => public}/locales/sl.json       |  0
 .../{private => public}/locales/sr.json       |  0
 .../{private => public}/locales/sv_SE.json    |  0
 .../{private => public}/locales/te.json       |  0
 .../{private => public}/locales/th.json       |  0
 .../{private => public}/locales/th_TH.json    |  0
 .../{private => public}/locales/tr.json       |  0
 .../{private => public}/locales/tr_TR.json    |  0
 .../{private => public}/locales/uk_UA.json    |  0
 .../{private => public}/locales/vi.json       |  0
 .../{private => public}/locales/vi_VN.json    |  0
 .../{private => public}/locales/zh_CN.json    |  0
 .../{private => public}/locales/zh_TW.json    |  0
 bigbluebutton-html5/transifex.sh              | 28 +++++---
 65 files changed, 158 insertions(+), 43 deletions(-)
 rename bigbluebutton-html5/{private => public}/locales/ar.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/az.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/bg_BG.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/ca.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/cs_CZ.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/da.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/de.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/el_GR.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/en.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/eo.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/es.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/es_ES.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/es_MX.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/et.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/eu.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/fa_IR.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/fi.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/fr.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/gl.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/he.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/hi_IN.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/hr.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/hu_HU.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/hy.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/id.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/it_IT.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/ja.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/ka.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/kk.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/km.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/kn.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/ko_KR.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/lo_LA.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/lt_LT.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/lv.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/mn_MN.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/nb_NO.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/nl.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/oc.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/pl_PL.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/pt.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/pt_BR.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/ro_RO.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/ru.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/ru_RU.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/sk_SK.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/sl.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/sr.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/sv_SE.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/te.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/th.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/th_TH.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/tr.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/tr_TR.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/uk_UA.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/vi.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/vi_VN.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/zh_CN.json (100%)
 rename bigbluebutton-html5/{private => public}/locales/zh_TW.json (100%)

diff --git a/bigbluebutton-html5/.gitignore b/bigbluebutton-html5/.gitignore
index 3a833eaf4f..b8bd4a6520 100755
--- a/bigbluebutton-html5/.gitignore
+++ b/bigbluebutton-html5/.gitignore
@@ -3,5 +3,7 @@ npm-debug.log
 node_modules/
 .meteor/dev_bundle
 tests/webdriverio/.testing-env
+public/locales/de_DE.json
+public/locales/ja_JP.json
 
 
diff --git a/bigbluebutton-html5/imports/startup/client/intl.jsx b/bigbluebutton-html5/imports/startup/client/intl.jsx
index 0d44ca2d67..c56fac96ba 100644
--- a/bigbluebutton-html5/imports/startup/client/intl.jsx
+++ b/bigbluebutton-html5/imports/startup/client/intl.jsx
@@ -63,6 +63,7 @@ class IntlStartup extends Component {
 
   fetchLocalizedMessages(locale, init = false) {
     const url = `./locale?locale=${locale}&init=${init}`;
+    const localesPath = 'locales';
 
     this.setState({ fetching: true }, () => {
       fetch(url)
@@ -73,11 +74,65 @@ class IntlStartup extends Component {
 
           return response.json();
         })
-        .then(({ messages, normalizedLocale }) => {
-          const dasherizedLocale = normalizedLocale.replace('_', '-');
-          this.setState({ messages, fetching: false, normalizedLocale: dasherizedLocale }, () => {
-            IntlStartup.saveLocale(dasherizedLocale);
-          });
+        .then(({ normalizedLocale, regionDefaultLocale }) => {
+          fetch(`${localesPath}/${DEFAULT_LANGUAGE}.json`)
+            .then((response) => {
+              if (!response.ok) {
+                return Promise.reject();
+              }
+              return response.json();
+            })
+            .then((messages) => {
+              if (regionDefaultLocale !== '') {
+                fetch(`${localesPath}/${regionDefaultLocale}.json`)
+                  .then((response) => {
+                    if (!response.ok) {
+                      return Promise.resolve();
+                    }
+                    return response.json();
+                  })
+                  .then((regionDefaultMessages) => {
+                    messages = Object.assign(messages, regionDefaultMessages);
+                    return messages;
+                  });
+              }
+
+              if (normalizedLocale !== DEFAULT_LANGUAGE && normalizedLocale !== regionDefaultLocale) {
+                fetch(`${localesPath}/${normalizedLocale}.json`)
+                  .then((response) => {
+                    if (!response.ok) {
+                      return Promise.reject();
+                    }
+                    return response.json();
+                  })
+                  .then((localeMessages) => {
+                    messages = Object.assign(messages, localeMessages);
+                    return messages;
+                  })
+                  .catch(() => {
+                    normalizedLocale = (regionDefaultLocale) || DEFAULT_LANGUAGE;
+                    const dasherizedLocale = normalizedLocale.replace('_', '-');
+                    this.setState({ messages, fetching: false, normalizedLocale: dasherizedLocale }, () => {
+                      IntlStartup.saveLocale(normalizedLocale);
+                    });
+                  });
+              }
+
+              return messages;
+            })
+            .then((messages) => {
+              const dasherizedLocale = normalizedLocale.replace('_', '-');
+              this.setState({ messages, fetching: false, normalizedLocale: dasherizedLocale }, () => {
+                IntlStartup.saveLocale(dasherizedLocale);
+              });
+            })
+            .catch(() => {
+              normalizedLocale = DEFAULT_LANGUAGE;
+              const dasherizedLocale = normalizedLocale.replace('_', '-');
+              this.setState({ fetching: false, normalizedLocale: dasherizedLocale }, () => {
+                IntlStartup.saveLocale(normalizedLocale);
+              });
+            });
         })
         .catch(() => {
           this.setState({ fetching: false, normalizedLocale: null }, () => {
diff --git a/bigbluebutton-html5/imports/startup/server/index.js b/bigbluebutton-html5/imports/startup/server/index.js
index 9be2dd4163..5f6508e6a3 100755
--- a/bigbluebutton-html5/imports/startup/server/index.js
+++ b/bigbluebutton-html5/imports/startup/server/index.js
@@ -12,7 +12,16 @@ import Redis from './redis';
 import setMinBrowserVersions from './minBrowserVersion';
 
 let guestWaitHtml = '';
-const AVAILABLE_LOCALES = fs.readdirSync('assets/app/locales');
+
+const env = Meteor.isDevelopment ? 'development' : 'production';
+
+const meteorRoot = fs.realpathSync(`${process.cwd()}/../`);
+
+const applicationRoot = (env === 'development')
+  ? fs.realpathSync(`${meteorRoot}'/../../../../public/locales/`)
+  : fs.realpathSync(`${meteorRoot}/../programs/web.browser/app/locales/`);
+
+const AVAILABLE_LOCALES = fs.readdirSync(`${applicationRoot}`);
 const FALLBACK_LOCALES = JSON.parse(Assets.getText('config/fallbackLocales.json'));
 
 process.on('uncaughtException', (err) => {
@@ -27,7 +36,6 @@ process.on('uncaughtException', (err) => {
 
 Meteor.startup(() => {
   const APP_CONFIG = Meteor.settings.public.app;
-  const env = Meteor.isDevelopment ? 'development' : 'production';
   const CDN_URL = APP_CONFIG.cdn;
   const instanceId = parseInt(process.env.INSTANCE_ID, 10) || 1;
 
@@ -191,7 +199,7 @@ WebApp.connectHandlers.use('/locale', (req, res) => {
   const browserLocale = override && req.query.init === 'true'
     ? override.split(/[-_]/g) : req.query.locale.split(/[-_]/g);
 
-  const localeList = [fallback];
+  let localeFile = fallback;
 
   const usableLocales = AVAILABLE_LOCALES
     .map(file => file.replace('.json', ''))
@@ -199,35 +207,29 @@ WebApp.connectHandlers.use('/locale', (req, res) => {
       ? [...locales, locale]
       : locales), []);
 
-  const regionDefault = usableLocales.find(locale => browserLocale[0] === locale);
-
-  if (regionDefault) localeList.push(regionDefault);
-  if (!regionDefault && usableLocales.length) localeList.push(usableLocales[0]);
-
   let normalizedLocale;
-  let messages = {};
 
   if (browserLocale.length > 1) {
     normalizedLocale = `${browserLocale[0]}_${browserLocale[1].toUpperCase()}`;
-    localeList.push(normalizedLocale);
+
+    const normDefault = usableLocales.find(locale => normalizedLocale === locale);
+    if (normDefault) localeFile = normDefault;
   }
 
-  localeList.forEach((locale) => {
-    try {
-      const data = Assets.getText(`locales/${locale}.json`);
-      messages = Object.assign(messages, JSON.parse(data));
-      normalizedLocale = locale;
-    } catch (e) {
-      Logger.info(`'Could not process locale ${locale}:${e}`);
-      // Getting here means the locale is not available in the current locale files.
-    }
-  });
+  const regionDefault = usableLocales.find(locale => browserLocale[0] === locale);
+
+  if (localeFile === fallback && regionDefault !== localeFile) {
+    localeFile = regionDefault;
+  }
 
   res.setHeader('Content-Type', 'application/json');
-  res.end(JSON.stringify({ normalizedLocale, messages }));
+  res.end(JSON.stringify({
+    normalizedLocale: localeFile,
+    regionDefaultLocale: (regionDefault && regionDefault !== localeFile) ? regionDefault : '',
+  }));
 });
 
-WebApp.connectHandlers.use('/locales', (req, res) => {
+WebApp.connectHandlers.use('/locale-list', (req, res) => {
   if (!avaibleLocalesNamesJSON) {
     avaibleLocalesNamesJSON = JSON.stringify(generateLocaleOptions());
   }
diff --git a/bigbluebutton-html5/imports/ui/components/legacy/component.jsx b/bigbluebutton-html5/imports/ui/components/legacy/component.jsx
index f6c049f345..b859270bd6 100755
--- a/bigbluebutton-html5/imports/ui/components/legacy/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/legacy/component.jsx
@@ -69,16 +69,17 @@ const FETCHING = 'fetching';
 const FALLBACK = 'fallback';
 const READY = 'ready';
 const supportedBrowsers = ['chrome', 'firefox', 'safari', 'opera', 'edge', 'yandex'];
+const DEFAULT_LANGUAGE = Meteor.settings.public.app.defaultSettings.application.fallbackLocale;
 
 export default class Legacy extends Component {
   constructor(props) {
     super(props);
 
     const locale = navigator.languages ? navigator.languages[0] : false
-      || navigator.language
-      || Meteor.settings.public.app.defaultSettings.application.fallbackLocale;
+      || navigator.language;
 
     const url = `./locale?locale=${locale}`;
+    const localesPath = 'locales';
 
     const that = this;
     this.state = { viewState: FETCHING };
@@ -90,9 +91,56 @@ export default class Legacy extends Component {
 
         return response.json();
       })
-      .then(({ messages, normalizedLocale }) => {
-        const dasherizedLocale = normalizedLocale.replace('_', '-');
-        that.setState({ messages, normalizedLocale: dasherizedLocale, viewState: READY });
+      .then(({ normalizedLocale, regionDefaultLocale }) => {
+        fetch(`${localesPath}/${DEFAULT_LANGUAGE}.json`)
+          .then((response) => {
+            if (!response.ok) {
+              return Promise.reject();
+            }
+            return response.json();
+          })
+          .then((messages) => {
+            if (regionDefaultLocale !== '') {
+              fetch(`${localesPath}/${regionDefaultLocale}.json`)
+                .then((response) => {
+                  if (!response.ok) {
+                    return Promise.resolve();
+                  }
+                  return response.json();
+                })
+                .then((regionDefaultMessages) => {
+                  messages = Object.assign(messages, regionDefaultMessages);
+                  this.setState({ messages});
+                });
+            }
+
+            if (normalizedLocale && normalizedLocale !== DEFAULT_LANGUAGE && normalizedLocale !== regionDefaultLocale) {
+              fetch(`${localesPath}/${normalizedLocale}.json`)
+                .then((response) => {
+                  if (!response.ok) {
+                    return Promise.reject();
+                  }
+                  return response.json();
+                })
+                .then((localeMessages) => {
+                  messages = Object.assign(messages, localeMessages);
+                  this.setState({ messages});
+                })
+                .catch(() => {
+                  normalizedLocale = (regionDefaultLocale) || DEFAULT_LANGUAGE;
+                  const dasherizedLocale = normalizedLocale.replace('_', '-');
+                  this.setState({ messages, normalizedLocale: dasherizedLocale, viewState: READY });
+                });
+            }
+            return messages;
+          })
+          .then((messages) => {
+            const dasherizedLocale = normalizedLocale.replace('_', '-');
+            this.setState({ messages, normalizedLocale: dasherizedLocale, viewState: READY });
+          })
+          .catch(() => {
+            that.setState({ viewState: FALLBACK });
+          });
       })
       .catch(() => {
         that.setState({ viewState: FALLBACK });
diff --git a/bigbluebutton-html5/imports/ui/components/settings/service.js b/bigbluebutton-html5/imports/ui/components/settings/service.js
index 85af45dddd..42698cb30c 100644
--- a/bigbluebutton-html5/imports/ui/components/settings/service.js
+++ b/bigbluebutton-html5/imports/ui/components/settings/service.js
@@ -27,7 +27,7 @@ const updateSettings = (obj, msg) => {
   }
 };
 
-const getAvailableLocales = () => fetch('./locales').then(locales => locales.json());
+const getAvailableLocales = () => fetch('./locale-list').then(locales => locales.json());
 
 export {
   getUserRoles,
diff --git a/bigbluebutton-html5/private/locales/ar.json b/bigbluebutton-html5/public/locales/ar.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/ar.json
rename to bigbluebutton-html5/public/locales/ar.json
diff --git a/bigbluebutton-html5/private/locales/az.json b/bigbluebutton-html5/public/locales/az.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/az.json
rename to bigbluebutton-html5/public/locales/az.json
diff --git a/bigbluebutton-html5/private/locales/bg_BG.json b/bigbluebutton-html5/public/locales/bg_BG.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/bg_BG.json
rename to bigbluebutton-html5/public/locales/bg_BG.json
diff --git a/bigbluebutton-html5/private/locales/ca.json b/bigbluebutton-html5/public/locales/ca.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/ca.json
rename to bigbluebutton-html5/public/locales/ca.json
diff --git a/bigbluebutton-html5/private/locales/cs_CZ.json b/bigbluebutton-html5/public/locales/cs_CZ.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/cs_CZ.json
rename to bigbluebutton-html5/public/locales/cs_CZ.json
diff --git a/bigbluebutton-html5/private/locales/da.json b/bigbluebutton-html5/public/locales/da.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/da.json
rename to bigbluebutton-html5/public/locales/da.json
diff --git a/bigbluebutton-html5/private/locales/de.json b/bigbluebutton-html5/public/locales/de.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/de.json
rename to bigbluebutton-html5/public/locales/de.json
diff --git a/bigbluebutton-html5/private/locales/el_GR.json b/bigbluebutton-html5/public/locales/el_GR.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/el_GR.json
rename to bigbluebutton-html5/public/locales/el_GR.json
diff --git a/bigbluebutton-html5/private/locales/en.json b/bigbluebutton-html5/public/locales/en.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/en.json
rename to bigbluebutton-html5/public/locales/en.json
diff --git a/bigbluebutton-html5/private/locales/eo.json b/bigbluebutton-html5/public/locales/eo.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/eo.json
rename to bigbluebutton-html5/public/locales/eo.json
diff --git a/bigbluebutton-html5/private/locales/es.json b/bigbluebutton-html5/public/locales/es.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/es.json
rename to bigbluebutton-html5/public/locales/es.json
diff --git a/bigbluebutton-html5/private/locales/es_ES.json b/bigbluebutton-html5/public/locales/es_ES.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/es_ES.json
rename to bigbluebutton-html5/public/locales/es_ES.json
diff --git a/bigbluebutton-html5/private/locales/es_MX.json b/bigbluebutton-html5/public/locales/es_MX.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/es_MX.json
rename to bigbluebutton-html5/public/locales/es_MX.json
diff --git a/bigbluebutton-html5/private/locales/et.json b/bigbluebutton-html5/public/locales/et.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/et.json
rename to bigbluebutton-html5/public/locales/et.json
diff --git a/bigbluebutton-html5/private/locales/eu.json b/bigbluebutton-html5/public/locales/eu.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/eu.json
rename to bigbluebutton-html5/public/locales/eu.json
diff --git a/bigbluebutton-html5/private/locales/fa_IR.json b/bigbluebutton-html5/public/locales/fa_IR.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/fa_IR.json
rename to bigbluebutton-html5/public/locales/fa_IR.json
diff --git a/bigbluebutton-html5/private/locales/fi.json b/bigbluebutton-html5/public/locales/fi.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/fi.json
rename to bigbluebutton-html5/public/locales/fi.json
diff --git a/bigbluebutton-html5/private/locales/fr.json b/bigbluebutton-html5/public/locales/fr.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/fr.json
rename to bigbluebutton-html5/public/locales/fr.json
diff --git a/bigbluebutton-html5/private/locales/gl.json b/bigbluebutton-html5/public/locales/gl.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/gl.json
rename to bigbluebutton-html5/public/locales/gl.json
diff --git a/bigbluebutton-html5/private/locales/he.json b/bigbluebutton-html5/public/locales/he.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/he.json
rename to bigbluebutton-html5/public/locales/he.json
diff --git a/bigbluebutton-html5/private/locales/hi_IN.json b/bigbluebutton-html5/public/locales/hi_IN.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/hi_IN.json
rename to bigbluebutton-html5/public/locales/hi_IN.json
diff --git a/bigbluebutton-html5/private/locales/hr.json b/bigbluebutton-html5/public/locales/hr.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/hr.json
rename to bigbluebutton-html5/public/locales/hr.json
diff --git a/bigbluebutton-html5/private/locales/hu_HU.json b/bigbluebutton-html5/public/locales/hu_HU.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/hu_HU.json
rename to bigbluebutton-html5/public/locales/hu_HU.json
diff --git a/bigbluebutton-html5/private/locales/hy.json b/bigbluebutton-html5/public/locales/hy.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/hy.json
rename to bigbluebutton-html5/public/locales/hy.json
diff --git a/bigbluebutton-html5/private/locales/id.json b/bigbluebutton-html5/public/locales/id.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/id.json
rename to bigbluebutton-html5/public/locales/id.json
diff --git a/bigbluebutton-html5/private/locales/it_IT.json b/bigbluebutton-html5/public/locales/it_IT.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/it_IT.json
rename to bigbluebutton-html5/public/locales/it_IT.json
diff --git a/bigbluebutton-html5/private/locales/ja.json b/bigbluebutton-html5/public/locales/ja.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/ja.json
rename to bigbluebutton-html5/public/locales/ja.json
diff --git a/bigbluebutton-html5/private/locales/ka.json b/bigbluebutton-html5/public/locales/ka.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/ka.json
rename to bigbluebutton-html5/public/locales/ka.json
diff --git a/bigbluebutton-html5/private/locales/kk.json b/bigbluebutton-html5/public/locales/kk.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/kk.json
rename to bigbluebutton-html5/public/locales/kk.json
diff --git a/bigbluebutton-html5/private/locales/km.json b/bigbluebutton-html5/public/locales/km.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/km.json
rename to bigbluebutton-html5/public/locales/km.json
diff --git a/bigbluebutton-html5/private/locales/kn.json b/bigbluebutton-html5/public/locales/kn.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/kn.json
rename to bigbluebutton-html5/public/locales/kn.json
diff --git a/bigbluebutton-html5/private/locales/ko_KR.json b/bigbluebutton-html5/public/locales/ko_KR.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/ko_KR.json
rename to bigbluebutton-html5/public/locales/ko_KR.json
diff --git a/bigbluebutton-html5/private/locales/lo_LA.json b/bigbluebutton-html5/public/locales/lo_LA.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/lo_LA.json
rename to bigbluebutton-html5/public/locales/lo_LA.json
diff --git a/bigbluebutton-html5/private/locales/lt_LT.json b/bigbluebutton-html5/public/locales/lt_LT.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/lt_LT.json
rename to bigbluebutton-html5/public/locales/lt_LT.json
diff --git a/bigbluebutton-html5/private/locales/lv.json b/bigbluebutton-html5/public/locales/lv.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/lv.json
rename to bigbluebutton-html5/public/locales/lv.json
diff --git a/bigbluebutton-html5/private/locales/mn_MN.json b/bigbluebutton-html5/public/locales/mn_MN.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/mn_MN.json
rename to bigbluebutton-html5/public/locales/mn_MN.json
diff --git a/bigbluebutton-html5/private/locales/nb_NO.json b/bigbluebutton-html5/public/locales/nb_NO.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/nb_NO.json
rename to bigbluebutton-html5/public/locales/nb_NO.json
diff --git a/bigbluebutton-html5/private/locales/nl.json b/bigbluebutton-html5/public/locales/nl.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/nl.json
rename to bigbluebutton-html5/public/locales/nl.json
diff --git a/bigbluebutton-html5/private/locales/oc.json b/bigbluebutton-html5/public/locales/oc.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/oc.json
rename to bigbluebutton-html5/public/locales/oc.json
diff --git a/bigbluebutton-html5/private/locales/pl_PL.json b/bigbluebutton-html5/public/locales/pl_PL.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/pl_PL.json
rename to bigbluebutton-html5/public/locales/pl_PL.json
diff --git a/bigbluebutton-html5/private/locales/pt.json b/bigbluebutton-html5/public/locales/pt.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/pt.json
rename to bigbluebutton-html5/public/locales/pt.json
diff --git a/bigbluebutton-html5/private/locales/pt_BR.json b/bigbluebutton-html5/public/locales/pt_BR.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/pt_BR.json
rename to bigbluebutton-html5/public/locales/pt_BR.json
diff --git a/bigbluebutton-html5/private/locales/ro_RO.json b/bigbluebutton-html5/public/locales/ro_RO.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/ro_RO.json
rename to bigbluebutton-html5/public/locales/ro_RO.json
diff --git a/bigbluebutton-html5/private/locales/ru.json b/bigbluebutton-html5/public/locales/ru.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/ru.json
rename to bigbluebutton-html5/public/locales/ru.json
diff --git a/bigbluebutton-html5/private/locales/ru_RU.json b/bigbluebutton-html5/public/locales/ru_RU.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/ru_RU.json
rename to bigbluebutton-html5/public/locales/ru_RU.json
diff --git a/bigbluebutton-html5/private/locales/sk_SK.json b/bigbluebutton-html5/public/locales/sk_SK.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/sk_SK.json
rename to bigbluebutton-html5/public/locales/sk_SK.json
diff --git a/bigbluebutton-html5/private/locales/sl.json b/bigbluebutton-html5/public/locales/sl.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/sl.json
rename to bigbluebutton-html5/public/locales/sl.json
diff --git a/bigbluebutton-html5/private/locales/sr.json b/bigbluebutton-html5/public/locales/sr.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/sr.json
rename to bigbluebutton-html5/public/locales/sr.json
diff --git a/bigbluebutton-html5/private/locales/sv_SE.json b/bigbluebutton-html5/public/locales/sv_SE.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/sv_SE.json
rename to bigbluebutton-html5/public/locales/sv_SE.json
diff --git a/bigbluebutton-html5/private/locales/te.json b/bigbluebutton-html5/public/locales/te.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/te.json
rename to bigbluebutton-html5/public/locales/te.json
diff --git a/bigbluebutton-html5/private/locales/th.json b/bigbluebutton-html5/public/locales/th.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/th.json
rename to bigbluebutton-html5/public/locales/th.json
diff --git a/bigbluebutton-html5/private/locales/th_TH.json b/bigbluebutton-html5/public/locales/th_TH.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/th_TH.json
rename to bigbluebutton-html5/public/locales/th_TH.json
diff --git a/bigbluebutton-html5/private/locales/tr.json b/bigbluebutton-html5/public/locales/tr.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/tr.json
rename to bigbluebutton-html5/public/locales/tr.json
diff --git a/bigbluebutton-html5/private/locales/tr_TR.json b/bigbluebutton-html5/public/locales/tr_TR.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/tr_TR.json
rename to bigbluebutton-html5/public/locales/tr_TR.json
diff --git a/bigbluebutton-html5/private/locales/uk_UA.json b/bigbluebutton-html5/public/locales/uk_UA.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/uk_UA.json
rename to bigbluebutton-html5/public/locales/uk_UA.json
diff --git a/bigbluebutton-html5/private/locales/vi.json b/bigbluebutton-html5/public/locales/vi.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/vi.json
rename to bigbluebutton-html5/public/locales/vi.json
diff --git a/bigbluebutton-html5/private/locales/vi_VN.json b/bigbluebutton-html5/public/locales/vi_VN.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/vi_VN.json
rename to bigbluebutton-html5/public/locales/vi_VN.json
diff --git a/bigbluebutton-html5/private/locales/zh_CN.json b/bigbluebutton-html5/public/locales/zh_CN.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/zh_CN.json
rename to bigbluebutton-html5/public/locales/zh_CN.json
diff --git a/bigbluebutton-html5/private/locales/zh_TW.json b/bigbluebutton-html5/public/locales/zh_TW.json
similarity index 100%
rename from bigbluebutton-html5/private/locales/zh_TW.json
rename to bigbluebutton-html5/public/locales/zh_TW.json
diff --git a/bigbluebutton-html5/transifex.sh b/bigbluebutton-html5/transifex.sh
index de1efe3eaa..b11dc50f7a 100755
--- a/bigbluebutton-html5/transifex.sh
+++ b/bigbluebutton-html5/transifex.sh
@@ -5,6 +5,14 @@ RED='\033[0;31m'
 GREEN='\033[1;32m'
 NC='\033[0m'
 SOURCE_LANGUAGE="en"
+LOCALES_DIRECTORY="./public/locales"
+PULL_SOURCE=false
+
+if [[ ! -e $LOCALES_DIRECTORY ]]; then
+    echo -e "Directory ${RED}$LOCALES_DIRECTORY${NC} does not exist, creating"
+    mkdir $LOCALES_DIRECTORY
+    PULL_SOURCE=true
+fi
 
 if [ "$#" = 0 ]
 then
@@ -33,19 +41,19 @@ else
           echo "$AVAILABLE_TRANSLATIONS" | while read l
             do
               LOCALE=$( echo "$l" | tr -d '[:space:]' )
-              if [ "$LOCALE" == "$SOURCE_LANGUAGE" ]; then
-                continue # do not pull the source file
+              if [ "$LOCALE" == "$SOURCE_LANGUAGE" ] && [ "$PULL_SOURCE" == false ]; then
+                continue # only pull source file if locales folder did not exist
               fi
               TRANSLATION=$(curl -L --user "$USER":"$PW" -X GET "https://www.transifex.com/api/2/project/bigbluebutton-v23-html5-client/resource/enjson/translation/$LOCALE/?mode=onlytranslated&file")
               NO_EMPTY_STRINGS=$(echo "$TRANSLATION" | sed '/: *\"\"/D' | sed '/}$/D')
-              if [ $(echo "$NO_EMPTY_STRINGS" | wc -l) == 1 ]
+              if [ $(echo "$NO_EMPTY_STRINGS" | wc -l) -lt 100 ]
               then
-                echo -e "${RED}WARN:${NC} translation file $LOCALE.json is empty\n${RED}WARN:${NC} $LOCALE.json not created"
+                echo -e "${RED}WARN:${NC} translation file $LOCALE.json contains less than 100 lines\n${RED}WARN:${NC} $LOCALE.json not created"
                 continue
               else
                 NO_TRAILING_COMMA=$(echo "$NO_EMPTY_STRINGS" | sed  '$ s/,$//')
-                echo "$NO_TRAILING_COMMA" > ./private/locales/"$LOCALE".json
-                echo -e "\n}\n" >> ./private/locales/"$LOCALE".json
+                echo "$NO_TRAILING_COMMA" > "$LOCALES_DIRECTORY/$LOCALE".json
+                echo -e "\n}\n" >> "$LOCALES_DIRECTORY/$LOCALE".json
                 echo -e "Added translation file $LOCALE.json : ${GREEN}✓${NC}"
               fi
             done
@@ -56,13 +64,13 @@ else
             echo -e "${RED}Err${NC}: Translations not found for locale ->${RED}$ARG${NC}<-"
           else
             NO_EMPTY_STRINGS=$(echo "$TRANSLATION" | sed '/: *\"\"/D' | sed '/}$/D')
-            if [ $(echo "$NO_EMPTY_STRINGS" | wc -l) == 1 ]
+            if [ $(echo "$NO_EMPTY_STRINGS" | wc -l) -lt 100 ]
             then
-              echo -e "${RED}WARN:${NC} translation file $ARG.json is empty\n${RED}WARN:${NC} $ARG.json not created"
+              echo -e "${RED}WARN:${NC} translation file $ARG.json contains less than 100 lines\n${RED}WARN:${NC} $ARG.json not created"
             else
               NO_TRAILING_COMMA=$(echo "$NO_EMPTY_STRINGS" | sed  '$ s/,//')
-              echo "$NO_TRAILING_COMMA" > ./private/locales/"$ARG".json
-              echo -e "\n}\n" >> ./private/locales/"$ARG".json
+              echo "$NO_TRAILING_COMMA" > "$LOCALES_DIRECTORY/$ARG".json
+              echo -e "\n}\n" >> "$LOCALES_DIRECTORY/$ARG".json
               echo -e "Added translation file $ARG.json :${GREEN} ✓${NC}"
             fi
           fi
-- 
GitLab