Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] Loading and setting fixes for i18n and RTL #11363

Merged
merged 18 commits into from Jul 20, 2018
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
84 changes: 84 additions & 0 deletions client/startup/i18n.js
@@ -0,0 +1,84 @@
/* globals isRtl */

import moment from 'moment';

const currentLanguage = new ReactiveVar();

Meteor.startup(() => {
TAPi18n.conf.i18n_files_route = Meteor._relativeToSiteRootUrl('/tap-i18n');
currentLanguage.set(localStorage.getItem('userLanguage'));

const availableLanguages = TAPi18n.getLanguages();

const filterLanguage = language => {
// Fix browsers having all-lowercase language settings eg. pt-br, en-us
const regex = /([a-z]{2})-([a-z]{2})/;
const matches = regex.exec(language);
if (matches) {
return `${ matches[1] }-${ matches[2].toUpperCase() }`;
}

return language;
};

const getBrowserLanguage = () => filterLanguage(window.navigator.userLanguage || window.navigator.language);

const loadMomentLocale = language => new Promise((resolve, reject) => {
if (moment.locales().includes(language.toLowerCase())) {
resolve(language);
return;
}

Meteor.call('loadLocale', language, (error, localeSrc) => {
if (error) {
reject(error);
return;
}

Function(localeSrc).call({ moment });
resolve(language);
});
});

const applyLanguage = (language = 'en') => {
language = filterLanguage(language);

if (!availableLanguages[language]) {
language = language.split('-').shift();
}

if (!language) {
return;
}

document.documentElement.classList[isRtl(language) ? 'add' : 'remove']('rtl');
TAPi18n.setLanguage(language);
loadMomentLocale(language).then(locale => moment.locale(locale), error => console.error(error));
};

const setLanguage = language => {
currentLanguage.set(filterLanguage(language));
localStorage.setItem('userLanguage', currentLanguage.get());
};

window.setLanguage = setLanguage;

window.defaultUserLanguage = () => RocketChat.settings.get('Language') || getBrowserLanguage() || 'en';

Tracker.autorun(() => {
const user = Meteor.userId() && RocketChat.models.Users.findOne(Meteor.userId());
const serverLanguage = RocketChat.settings.get('Language');
const userLanguage = user && user.language;
const defaultLanguage = userLanguage || serverLanguage || 'en';

if (!currentLanguage.get()) {
setLanguage(defaultLanguage);
}

if (userLanguage && userLanguage !== currentLanguage.get()) {
setLanguage(userLanguage);
}

applyLanguage(currentLanguage.get());
});
});
63 changes: 1 addition & 62 deletions client/startup/startup.js
@@ -1,6 +1,5 @@
/* globals UserPresence, fireGlobalEvent, isRtl */
/* globals UserPresence, fireGlobalEvent */

import moment from 'moment';
import toastr from 'toastr';
import hljs from 'highlight.js';
import 'highlight.js/styles/github.css';
Expand All @@ -22,57 +21,6 @@ Meteor.startup(function() {
window.lastMessageWindow = {};
window.lastMessageWindowHistory = {};

TAPi18n.conf.i18n_files_route = Meteor._relativeToSiteRootUrl('/tap-i18n');

const defaultAppLanguage = () => {
let lng = window.navigator.userLanguage || window.navigator.language || 'en';
// Fix browsers having all-lowercase language settings eg. pt-br, en-us
const re = /([a-z]{2}-)([a-z]{2})/;
if (re.test(lng)) {
lng = lng.replace(re, (match, ...parts) => {
return parts[0] + parts[1].toUpperCase();
});
}
return lng;
};

window.defaultUserLanguage = () => RocketChat.settings.get('Language') || defaultAppLanguage();

const availableLanguages = TAPi18n.getLanguages();
const loadedLanguages = [];

window.setLanguage = function(language) {
if (!language) {
return;
}

if (loadedLanguages.indexOf(language) > -1) {
return;
}

loadedLanguages.push(language);

if (isRtl(language)) {
$('html').addClass('rtl');
} else {
$('html').removeClass('rtl');
}

if (!availableLanguages[language]) {
language = language.split('-').shift();
}

TAPi18n.setLanguage(language);

language = language.toLowerCase();
if (language !== 'en') {
Meteor.call('loadLocale', language, (err, localeFn) => {
Function(localeFn).call({moment});
moment.locale(language);
});
}
};

Tracker.autorun(function(computation) {
if (!Meteor.userId() && !RocketChat.settings.get('Accounts_AllowAnonymousRead')) {
return;
Expand Down Expand Up @@ -114,13 +62,4 @@ Meteor.startup(function() {
fireGlobalEvent('status-changed', status);
}
});

Tracker.autorun(() => {
const userLanguage = Meteor.user() && Meteor.user().language || RocketChat.settings.get('Language') || 'en';

if (loadedLanguages.length === 0 || localStorage.getItem('userLanguage') !== userLanguage) {
localStorage.setItem('userLanguage', userLanguage);
window.setLanguage(userLanguage);
}
});
});
5 changes: 1 addition & 4 deletions packages/rocketchat-ui-account/client/accountPreferences.js
Expand Up @@ -41,11 +41,8 @@ Template.accountPreferences.helpers({
.map(([ key, language ]) => ({ ...language, key: key.toLowerCase() }))
.sort((a, b) => a.key - b.key);

const appLanguageKey = RocketChat.settings.get('Language') || 'en';
const appLanguage = result.filter(({ key }) => key === appLanguageKey.toLowerCase())[0];

result.unshift({
'name': appLanguage ? `Default (${ appLanguage.name })` : 'Default',
'name': 'Default',
'en': 'Default',
'key': ''
});
Expand Down
14 changes: 11 additions & 3 deletions packages/rocketchat-ui-admin/client/admin.js
Expand Up @@ -414,13 +414,21 @@ Template.admin.events({
const group = FlowRouter.getParam('group');
const query = { group, changed: true };
const settings = TempSettings.find(query, { fields: { _id: 1, value: 1, editor: 1 }}).fetch();
if (!_.isEmpty(settings)) {
RocketChat.settings.batchSet(settings, function(err) {
if (settings && settings.length > 0) {
RocketChat.settings.batchSet(settings, (err) => {
if (err) {
return handleError(err);
}
TempSettings.update({ changed: true }, { $unset: { changed: 1 }});
toastr.success(TAPi18n.__('Settings_updated'));

if (settings.some(({ _id }) => _id === 'Language')) {
const lng = Meteor.user().language
|| settings.filter(({ _id }) => _id === 'Language').shift().value
|| 'en';
TAPi18n._loadLanguage(lng).then(() => toastr.success(TAPi18n.__('Settings_updated', { lng })));
} else {
toastr.success(TAPi18n.__('Settings_updated'));
}
});
}
},
Expand Down
6 changes: 5 additions & 1 deletion packages/rocketchat-ui-login/client/login/footer.html
@@ -1,5 +1,9 @@
<template name='loginFooter'>
<footer>
{{#if LanguageVersion}}<div class="switch-language"><button class="switch-language">{{LanguageVersion}}</button></div>{{/if}}
{{#if languageVersion}}
<div class="switch-language">
<button class="js-switch-language">{{languageVersion}}</button>
</div>
{{/if}}
</footer>
</template>
56 changes: 29 additions & 27 deletions packages/rocketchat-ui-login/client/login/footer.js
@@ -1,35 +1,37 @@
/*globals defaultUserLanguage */
Template.loginFooter.helpers({
LanguageVersion() {
if (Template.instance().languageVersion.get()) {
return TAPi18n.__('Language_Version', {
lng: Template.instance().languageVersion.get()
});
Template.loginFooter.onCreated(function() {
this.suggestedLanguage = new ReactiveVar();

this.suggestAnotherLanguageFor = language => {
const loadAndSetSuggestedLanguage = language => TAPi18n._loadLanguage(language)
.then(() => this.suggestedLanguage.set(language));

const serverLanguage = RocketChat.settings.get('Language');

if (serverLanguage !== language) {
loadAndSetSuggestedLanguage(serverLanguage || 'en');
} else if (!/^en/.test(language)) {
loadAndSetSuggestedLanguage('en');
} else {
this.suggestedLanguage.set(undefined);
}
}
};

const currentLanguage = localStorage.getItem('userLanguage');
this.suggestAnotherLanguageFor(currentLanguage);
});

Template.loginFooter.events({
'click button.switch-language'(e, t) {
const userLanguage = t.languageVersion.get();
localStorage.setItem('userLanguage', userLanguage);
TAPi18n.setLanguage(userLanguage);
moment.locale(userLanguage);
return t.languageVersion.set(userLanguage !== defaultUserLanguage() ? defaultUserLanguage() : 'en');
Template.loginFooter.helpers({
languageVersion() {
const lng = Template.instance().suggestedLanguage.get();
return lng && TAPi18n.__('Language_Version', { lng });
}
});

Template.loginFooter.onCreated(function() {
const self = this;
this.languageVersion = new ReactiveVar;
const userLanguage = localStorage.getItem('userLanguage');
if (userLanguage !== defaultUserLanguage()) {
return TAPi18n._loadLanguage(defaultUserLanguage()).done(function() {
return self.languageVersion.set(defaultUserLanguage());
});
} else if (userLanguage.indexOf('en') !== 0) {
return TAPi18n._loadLanguage('en').done(function() {
return self.languageVersion.set('en');
});
Template.loginFooter.events({
'click button.js-switch-language'(e, t) {
const language = t.suggestedLanguage.get();
window.setLanguage(language);
t.suggestAnotherLanguageFor(language);
return false;
}
});
3 changes: 1 addition & 2 deletions packages/rocketchat-ui-master/client/main.js
@@ -1,4 +1,4 @@
/* globals toolbarSearch, menu, isRtl, fireGlobalEvent, CachedChatSubscription, DynamicCss */
/* globals toolbarSearch, menu, fireGlobalEvent, CachedChatSubscription, DynamicCss */
import Clipboard from 'clipboard';
import s from 'underscore.string';

Expand Down Expand Up @@ -191,7 +191,6 @@ Template.main.events({
});

Template.main.onRendered(function() {
document.body.classList[(isRtl(localStorage.getItem('userLanguage'))? 'add': 'remove')]('rtl');
$('#initial-page-loading').remove();
window.addEventListener('focus', function() {
return Meteor.setTimeout(function() {
Expand Down