converted i18nservice properly

This commit is contained in:
Kyle Spearrin 2018-04-11 14:52:49 -04:00
parent 222b58f440
commit 3ebb09fa8d
6 changed files with 133 additions and 104 deletions

View File

@ -60,8 +60,7 @@ import AutofillService from '../services/autofill.service';
import BrowserMessagingService from '../services/browserMessaging.service';
import BrowserPlatformUtilsService from '../services/browserPlatformUtils.service';
import BrowserStorageService from '../services/browserStorage.service';
import i18nService from '../services/i18n.service';
import I18n2Service from '../services/i18n2.service';
import I18nService from '../services/i18n.service';
import { AutofillService as AutofillServiceAbstraction } from '../services/abstractions/autofill.service';
@ -69,8 +68,7 @@ export default class MainBackground {
messagingService: MessagingServiceAbstraction;
storageService: StorageServiceAbstraction;
secureStorageService: StorageServiceAbstraction;
i18nService: any;
i18n2Service: I18nServiceAbstraction;
i18nService: I18nServiceAbstraction;
platformUtilsService: PlatformUtilsServiceAbstraction;
utilsService: UtilsServiceAbstraction;
constantsService: ConstantsService;
@ -117,12 +115,10 @@ export default class MainBackground {
this.utilsService = new UtilsService();
this.messagingService = new BrowserMessagingService();
this.platformUtilsService = new BrowserPlatformUtilsService(this.messagingService);
const delayi18nLoad = this.platformUtilsService.isEdge() || this.platformUtilsService.isSafari() ? 1000 : 0;
this.storageService = new BrowserStorageService(this.platformUtilsService, false);
this.secureStorageService = new BrowserStorageService(this.platformUtilsService, true);
this.i18nService = i18nService(this.platformUtilsService);
this.i18n2Service = new I18n2Service(window.navigator.language, this.i18nService);
this.constantsService = new ConstantsService(this.i18nService, delayi18nLoad);
this.i18nService = new I18nService(BrowserApi.getUILanguage(window),
BrowserApi.isSafariApi ? './_locales/' : null);
this.cryptoService = new CryptoService(this.storageService, this.secureStorageService);
this.tokenService = new TokenService(this.storageService);
this.appIdService = new AppIdService(this.storageService);
@ -132,11 +128,11 @@ export default class MainBackground {
this.userService = new UserService(this.tokenService, this.storageService);
this.settingsService = new SettingsService(this.userService, this.storageService);
this.cipherService = new CipherService(this.cryptoService, this.userService, this.settingsService,
this.apiService, this.storageService, this.i18n2Service, this.platformUtilsService, this.utilsService);
this.apiService, this.storageService, this.i18nService, this.platformUtilsService, this.utilsService);
this.folderService = new FolderService(this.cryptoService, this.userService,
() => this.i18nService.noneFolder, this.apiService, this.storageService, this.i18n2Service);
() => this.i18nService.t('noneFolder'), this.apiService, this.storageService, this.i18nService);
this.collectionService = new CollectionService(this.cryptoService, this.userService, this.storageService,
this.i18n2Service);
this.i18nService);
this.lockService = new LockService(this.cipherService, this.folderService, this.collectionService,
this.cryptoService, this.platformUtilsService, this.storageService, this.messagingService, async () => {
await this.setIcon();
@ -342,7 +338,7 @@ export default class MainBackground {
id: 'autofill',
parentId: 'root',
contexts: ['all'],
title: this.i18nService.autoFill,
title: this.i18nService.t('autoFill'),
});
// Firefox & Edge do not support writing to the clipboard from background
@ -352,7 +348,7 @@ export default class MainBackground {
id: 'copy-username',
parentId: 'root',
contexts: ['all'],
title: this.i18nService.copyUsername,
title: this.i18nService.t('copyUsername'),
});
await this.contextMenusCreate({
@ -360,7 +356,7 @@ export default class MainBackground {
id: 'copy-password',
parentId: 'root',
contexts: ['all'],
title: this.i18nService.copyPassword,
title: this.i18nService.t('copyPassword'),
});
await this.contextMenusCreate({
@ -373,7 +369,7 @@ export default class MainBackground {
id: 'generate-password',
parentId: 'root',
contexts: ['all'],
title: this.i18nService.generatePasswordCopied,
title: this.i18nService.t('generatePasswordCopied'),
});
}
@ -411,7 +407,7 @@ export default class MainBackground {
theText = '9+';
} else {
if (contextMenuEnabled) {
await this.loadNoLoginsContextMenuOptions(this.i18nService.noMatchingLogins);
await this.loadNoLoginsContextMenuOptions(this.i18nService.t('noMatchingLogins'));
}
}
@ -424,7 +420,7 @@ export default class MainBackground {
private async loadMenuAndUpdateBadgeForLockedState(contextMenuEnabled: boolean) {
if (contextMenuEnabled) {
await this.loadNoLoginsContextMenuOptions(this.i18nService.vaultLocked);
await this.loadNoLoginsContextMenuOptions(this.i18nService.t('vaultLocked'));
}
const tabs = await BrowserApi.getActiveTabs();

View File

@ -7,6 +7,8 @@ import { LoginView } from 'jslib/models/view/loginView';
import { ConstantsService } from 'jslib/services/constants.service';
import { UtilsService } from 'jslib/services/utils.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { Analytics } from 'jslib/misc';
import {
@ -30,7 +32,7 @@ export default class RuntimeBackground {
constructor(private main: MainBackground, private autofillService: AutofillService,
private cipherService: CipherService, private platformUtilsService: BrowserPlatformUtilsService,
private storageService: StorageService, private i18nService: any, private analytics: Analytics) {
private storageService: StorageService, private i18nService: I18nService, private analytics: Analytics) {
this.isSafari = this.platformUtilsService.isSafari();
this.runtime = this.isSafari ? safari.application : chrome.runtime;
@ -357,13 +359,13 @@ export default class RuntimeBackground {
ConstantsService.enableAutoFillOnPageLoadKey);
} else if (responseCommand === 'notificationBarFrameDataResponse') {
responseData.i18n = {
appName: this.i18nService.appName,
close: this.i18nService.close,
yes: this.i18nService.yes,
never: this.i18nService.never,
notificationAddSave: this.i18nService.notificationAddSave,
notificationNeverSave: this.i18nService.notificationNeverSave,
notificationAddDesc: this.i18nService.notificationAddDesc,
appName: this.i18nService.t('appName'),
close: this.i18nService.t('close'),
yes: this.i18nService.t('yes'),
never: this.i18nService.t('never'),
notificationAddSave: this.i18nService.t('notificationAddSave'),
notificationNeverSave: this.i18nService.t('notificationNeverSave'),
notificationAddDesc: this.i18nService.t('notificationAddDesc'),
};
}

View File

@ -1,6 +1,6 @@
export class BrowserApi {
static isSafariApi: boolean = (typeof safari !== 'undefined') &&
navigator.userAgent.indexOf(' Safari/') !== -1 && navigator.userAgent.indexOf('Chrome') === -1;
navigator.userAgent.indexOf(' Safari/') !== -1 && navigator.userAgent.indexOf('Chrome') === -1;
static isChromeApi: boolean = !BrowserApi.isSafariApi && (typeof chrome !== 'undefined');
static async getTabFromCurrentWindowId(): Promise<any> {
@ -264,4 +264,12 @@ export class BrowserApi {
static gaFilter() {
return BrowserApi.isSafariApi && safari.application.activeBrowserWindow.activeTab.private;
}
static getUILanguage(win: Window) {
if (BrowserApi.isSafariApi) {
return win.navigator.language;
} else {
return chrome.i18n.getUILanguage();
}
}
}

View File

@ -57,7 +57,7 @@ export const messagingService = new BrowserMessagingService();
export const authService = new AuthService(getBgService<CryptoService>('cryptoService')(),
getBgService<ApiService>('apiService')(), getBgService<UserService>('userService')(),
getBgService<TokenService>('tokenService')(), getBgService<AppIdService>('appIdService')(),
getBgService<I18nService>('i18n2Service')(), getBgService<PlatformUtilsService>('platformUtilsService')(),
getBgService<I18nService>('i18nService')(), getBgService<PlatformUtilsService>('platformUtilsService')(),
getBgService<ConstantsService>('constantsService')(), messagingService);
export function initFactory(i18nService: I18nService, storageService: StorageService,
@ -102,7 +102,7 @@ export function initFactory(i18nService: I18nService, storageService: StorageSer
{ provide: EnvironmentService, useFactory: getBgService<EnvironmentService>('environmentService'), deps: [] },
{ provide: TotpService, useFactory: getBgService<TotpService>('totpService'), deps: [] },
{ provide: TokenService, useFactory: getBgService<TokenService>('tokenService'), deps: [] },
{ provide: I18nService, useFactory: getBgService<I18nService>('i18n2Service'), deps: [] },
{ provide: I18nService, useFactory: getBgService<I18nService>('i18nService'), deps: [] },
{ provide: UtilsService, useFactory: getBgService<UtilsService>('utilsService'), deps: [] },
{ provide: CryptoService, useFactory: getBgService<CryptoService>('cryptoService'), deps: [] },
{

View File

@ -1,69 +1,121 @@
import { PlatformUtilsService } from 'jslib/abstractions';
import { I18nService as I18nServiceAbstraction } from 'jslib/abstractions/i18n.service';
// First locale is the default (English)
const SupportedLocales = [
const SupportedTranslationLocales = [
'en', 'cs', 'da', 'de', 'es', 'et', 'fi', 'fr', 'hr', 'hu', 'id', 'it', 'ja',
'nb', 'nl', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru', 'sk', 'sv', 'tr', 'uk', 'vi',
'zh-CN', 'zh-TW',
];
export default function i18nService(platformUtilsService: PlatformUtilsService) {
const defaultMessages: any = {};
const localeMessages: any = {};
export default class I18nService implements I18nServiceAbstraction {
defaultMessages: any = {};
localeMessages: any = {};
locale: string;
translationLocale: string;
collator: Intl.Collator;
inited: boolean;
if (platformUtilsService.isEdge()) {
loadMessages('../_locales/', 'en', localeMessages,
(prop: string, message: string) => chrome.i18n.getMessage(prop));
return localeMessages;
}
constructor(private systemLanguage: string, private localesDirectory: string) { }
if (platformUtilsService.isSafari()) {
let lang = navigator.language;
if (SupportedLocales.indexOf(lang) === -1) {
lang = lang.slice(0, 2);
async init(locale?: string) {
if (this.inited) {
throw new Error('i18n already initialized.');
}
if (SupportedLocales.indexOf(lang) === -1) {
lang = SupportedLocales[0];
this.inited = true;
this.locale = this.translationLocale = locale != null ? locale : this.systemLanguage;
this.collator = new Intl.Collator(this.locale);
if (SupportedTranslationLocales.indexOf(this.translationLocale) === -1) {
this.translationLocale = this.translationLocale.slice(0, 2);
if (SupportedTranslationLocales.indexOf(this.translationLocale) === -1) {
this.translationLocale = SupportedTranslationLocales[0];
}
}
const dir = './_locales/';
loadMessages(dir, lang, localeMessages, (prop: string, message: string) => message);
if (lang !== SupportedLocales[0]) {
loadMessages(dir, SupportedLocales[0], defaultMessages,
(prop: string, message: string) => message);
if (this.localesDirectory != null) {
await this.loadMessages(this.localesDirectory, this.translationLocale, this.localeMessages);
if (this.translationLocale !== SupportedTranslationLocales[0]) {
await this.loadMessages(this.localesDirectory, SupportedTranslationLocales[0], this.defaultMessages);
}
}
}
return new Proxy({}, {
get: (target, name) => {
const id = name.toString();
t(id: string, p1?: string, p2?: string, p3?: string): string {
return this.translate(id, p1, p2, p3);
}
if (platformUtilsService.isSafari()) {
if (localeMessages.hasOwnProperty(id) && localeMessages[id]) {
return localeMessages[id];
} else if (defaultMessages.hasOwnProperty(id) && defaultMessages[id]) {
return defaultMessages[id];
translate(id: string, p1?: string, p2?: string, p3?: string): string {
if (this.localesDirectory == null) {
const placeholders: string[] = [];
if (p1 != null) {
placeholders.push(p1);
}
if (p2 != null) {
placeholders.push(p2);
}
if (p3 != null) {
placeholders.push(p3);
}
if (placeholders.length) {
return chrome.i18n.getMessage(id, placeholders);
} else {
return chrome.i18n.getMessage(id);
}
}
let result: string;
if (this.localeMessages.hasOwnProperty(id) && this.localeMessages[id]) {
result = this.localeMessages[id];
} else if (this.defaultMessages.hasOwnProperty(id) && this.defaultMessages[id]) {
result = this.defaultMessages[id];
} else {
result = '';
}
if (result !== '') {
if (p1 != null) {
result = result.split('__$1__').join(p1);
}
if (p2 != null) {
result = result.split('__$2__').join(p2);
}
if (p3 != null) {
result = result.split('__$3__').join(p3);
}
}
return result;
}
private async loadMessages(localesDir: string, locale: string, messagesObj: any): Promise<any> {
const formattedLocale = locale.replace('-', '_');
const file = await fetch(localesDir + formattedLocale + '/messages.json');
const locales = await file.json();
for (const prop in locales) {
if (!locales.hasOwnProperty(prop)) {
continue;
}
messagesObj[prop] = locales[prop].message;
if (locales[prop].placeholders) {
for (const placeProp in locales[prop].placeholders) {
if (!locales[prop].placeholders.hasOwnProperty(placeProp) ||
!locales[prop].placeholders[placeProp].content) {
continue;
}
const replaceToken = '\\$' + placeProp.toUpperCase() + '\\$';
let replaceContent = locales[prop].placeholders[placeProp].content;
if (replaceContent === '$1' || replaceContent === '$2' || replaceContent === '$3') {
replaceContent = '__' + replaceContent + '__';
}
messagesObj[prop] = messagesObj[prop].replace(new RegExp(replaceToken, 'g'), replaceContent);
}
return '';
}
return chrome.i18n.getMessage(id);
},
set: (target, name, value) => {
return false;
},
});
}
async function loadMessages(localesDir: string, locale: string, messagesObj: any,
messageCallback: (prop: string, message: string) => string): Promise<any> {
const formattedLocale = locale.replace('-', '_');
const file = await fetch(localesDir + formattedLocale + '/messages.json');
const locales = await file.json();
for (const prop in locales) {
if (locales.hasOwnProperty(prop)) {
messagesObj[prop] = messageCallback(prop, locales[prop].message);
}
}
}

View File

@ -1,29 +0,0 @@
import { I18nService as I18nServiceAbstraction } from 'jslib/abstractions/i18n.service';
export default class I18n2Service implements I18nServiceAbstraction {
locale: string;
translationLocale: string;
collator: Intl.Collator;
inited: boolean;
constructor(private systemLanguage: string, private i18nService: any) {
}
async init(locale?: string) {
if (this.inited) {
throw new Error('i18n already initialized.');
}
this.inited = true;
this.locale = this.translationLocale = locale != null ? locale : this.systemLanguage;
this.collator = new Intl.Collator(this.locale);
}
t(id: string, p1?: string, p2?: string, p3?: string): string {
return this.translate(id);
}
translate(id: string, p1?: string, p2?: string, p3?: string): string {
return this.i18nService[id];
}
}