1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-27 12:36:14 +01:00

i18n service and helpers

This commit is contained in:
Kyle Spearrin 2018-01-24 14:59:03 -05:00
parent 0e33ad9b0b
commit 2ab23c2c9e
9 changed files with 124 additions and 14 deletions

View File

@ -0,0 +1,5 @@
{
"hello": {
"message": "hello"
}
}

View File

@ -0,0 +1,5 @@
{
"hello": {
"message": "hola"
}
}

View File

@ -18,7 +18,6 @@ export class LoginComponent implements OnInit {
masterPassword: string = ''; masterPassword: string = '';
constructor(private authService: AuthService, private router: Router) { constructor(private authService: AuthService, private router: Router) {
} }
ngOnInit() { ngOnInit() {

View File

@ -11,6 +11,7 @@ import { AppComponent } from './app.component';
import { CiphersComponent } from './vault/ciphers.component'; import { CiphersComponent } from './vault/ciphers.component';
import { FallbackSrcDirective } from './directives/fallback-src.directive'; import { FallbackSrcDirective } from './directives/fallback-src.directive';
import { GroupingsComponent } from './vault/groupings.component'; import { GroupingsComponent } from './vault/groupings.component';
import { I18nPipe } from './pipes/i18n.pipe';
import { IconComponent } from './vault/icon.component'; import { IconComponent } from './vault/icon.component';
import { LoginComponent } from './accounts/login.component'; import { LoginComponent } from './accounts/login.component';
import { StopClickDirective } from './directives/stop-click.directive'; import { StopClickDirective } from './directives/stop-click.directive';
@ -30,6 +31,7 @@ import { ViewComponent } from './vault/view.component';
CiphersComponent, CiphersComponent,
FallbackSrcDirective, FallbackSrcDirective,
GroupingsComponent, GroupingsComponent,
I18nPipe,
IconComponent, IconComponent,
LoginComponent, LoginComponent,
StopClickDirective, StopClickDirective,

View File

@ -0,0 +1,18 @@
import {
Pipe,
PipeTransform,
} from '@angular/core';
import { I18nService } from '../../services/i18n.service';
@Pipe({
name: 'i18n',
})
export class I18nPipe implements PipeTransform {
constructor(private i18nService: I18nService) {
}
transform(id: string): string {
return this.i18nService.t(id);
}
}

View File

@ -1,11 +1,15 @@
import { webFrame } from 'electron'; import { webFrame } from 'electron';
import { NgModule } from '@angular/core'; import {
APP_INITIALIZER,
NgModule
} from '@angular/core';
import { DesktopMessagingService } from '../../services/desktopMessaging.service'; import { DesktopMessagingService } from '../../services/desktopMessaging.service';
import { DesktopPlatformUtilsService } from '../../services/desktopPlatformUtils.service'; import { DesktopPlatformUtilsService } from '../../services/desktopPlatformUtils.service';
import { DesktopStorageService } from '../../services/desktopStorage.service'; import { DesktopStorageService } from '../../services/desktopStorage.service';
import { DesktopSecureStorageService } from '../../services/desktopSecureStorage.service'; import { DesktopSecureStorageService } from '../../services/desktopSecureStorage.service';
import { I18nService } from '../../services/i18n.service';
import { import {
ApiService, ApiService,
@ -52,6 +56,7 @@ import {
webFrame.registerURLSchemeAsPrivileged('file'); webFrame.registerURLSchemeAsPrivileged('file');
const i18nService = new I18nService(window, './_locales');
const utilsService = new UtilsService(); const utilsService = new UtilsService();
const platformUtilsService = new DesktopPlatformUtilsService(); const platformUtilsService = new DesktopPlatformUtilsService();
const messagingService = new DesktopMessagingService(); const messagingService = new DesktopMessagingService();
@ -69,7 +74,7 @@ const settingsService = new SettingsService(userService, storageService);
const cipherService = new CipherService(cryptoService, userService, settingsService, const cipherService = new CipherService(cryptoService, userService, settingsService,
apiService, storageService); apiService, storageService);
const folderService = new FolderService(cryptoService, userService, const folderService = new FolderService(cryptoService, userService,
() => 'No Folder', apiService, storageService); () => i18nService.t('noneFolder'), apiService, storageService);
const collectionService = new CollectionService(cryptoService, userService, storageService); const collectionService = new CollectionService(cryptoService, userService, storageService);
const lockService = new LockService(cipherService, folderService, collectionService, const lockService = new LockService(cipherService, folderService, collectionService,
cryptoService, platformUtilsService, storageService, cryptoService, platformUtilsService, storageService,
@ -89,6 +94,10 @@ environmentService.setUrlsFromStorage().then(() => {
return syncService.fullSync(true); return syncService.fullSync(true);
}); });
function initFactory(i18n: I18nService): Function {
return () => i18n.init();
}
@NgModule({ @NgModule({
imports: [], imports: [],
declarations: [], declarations: [],
@ -98,6 +107,13 @@ environmentService.setUrlsFromStorage().then(() => {
{ provide: FolderServiceAbstraction, useValue: folderService }, { provide: FolderServiceAbstraction, useValue: folderService },
{ provide: CollectionServiceAbstraction, useValue: collectionService }, { provide: CollectionServiceAbstraction, useValue: collectionService },
{ provide: EnvironmentServiceAbstraction, useValue: environmentService }, { provide: EnvironmentServiceAbstraction, useValue: environmentService },
{ provide: I18nService, useValue: i18nService },
{
provide: APP_INITIALIZER,
useFactory: initFactory,
deps: [I18nService],
multi: true
}
], ],
}) })
export class ServicesModule { export class ServicesModule {

View File

@ -9,17 +9,19 @@
<span class="row-label">Name</span> <span class="row-label">Name</span>
{{cipher.name}} {{cipher.name}}
</div> </div>
<div class="box-content-row"> <div *ngIf="cipher.login">
<span class="row-label">URI</span> <div class="box-content-row">
{{cipher.login.uri}} <span class="row-label">URI</span>
</div> {{cipher.login.uri}}
<div class="box-content-row"> </div>
<span class="row-label">Username</span> <div class="box-content-row">
{{cipher.login.username}} <span class="row-label">Username</span>
</div> {{cipher.login.username}}
<div class="box-content-row"> </div>
<span class="row-label">Password</span> <div class="box-content-row">
{{cipher.login.password}} <span class="row-label">Password</span>
{{cipher.login.password}}
</div>
</div> </div>
</div> </div>
<div class="box-footer"> <div class="box-footer">

View File

@ -0,0 +1,62 @@
// First locale is the default (English)
const SupportedLocales = [
'en', 'es',
];
export class I18nService {
defaultMessages: any = {};
localeMessages: any = {};
systemLanguage: string;
language: string;
inited: boolean;
constructor(win: Window, private localesDirectory: string) {
this.systemLanguage = win.navigator.language;
}
async init(language?: string) {
if (this.inited) {
throw new Error('i18n already initialized.');
}
this.inited = true;
this.language = language != null ? language : this.systemLanguage;
if (SupportedLocales.indexOf(this.language) === -1) {
this.language = this.language.slice(0, 2);
if (SupportedLocales.indexOf(this.language) === -1) {
this.language = SupportedLocales[0];
}
}
await this.loadMessages(this.language, this.localeMessages);
if (this.language !== SupportedLocales[0]) {
await this.loadMessages(SupportedLocales[0], this.defaultMessages);
}
}
t(id: string): string {
return this.translation(id);
}
translation(id: string): string {
if (this.localeMessages.hasOwnProperty(id) && this.localeMessages[id]) {
return this.localeMessages[id];
} else if (this.defaultMessages.hasOwnProperty(id) && this.defaultMessages[id]) {
return this.defaultMessages[id];
}
return '';
}
private async loadMessages(locale: string, messagesObj: any): Promise<any> {
const formattedLocale = locale.replace('-', '_');
const file = await fetch(this.localesDirectory + '/' + formattedLocale + '/messages.json');
const locales = await file.json();
for (const prop in locales) {
if (locales.hasOwnProperty(prop)) {
messagesObj[prop] = locales[prop].message;
}
}
}
}

View File

@ -57,6 +57,7 @@ const main = {
new CopyWebpackPlugin([ new CopyWebpackPlugin([
'./src/package.json', './src/package.json',
{ from: './src/images', to: 'images' }, { from: './src/images', to: 'images' },
{ from: './src/_locales', to: '_locales' },
]), ]),
], ],
externals: [nodeExternals()] externals: [nodeExternals()]