LP#1775466 Translation widget; apply OpenSRF.locale
authorBill Erickson <berickxx@gmail.com>
Mon, 13 Aug 2018 15:08:14 +0000 (11:08 -0400)
committerBill Erickson <berickxx@gmail.com>
Mon, 13 Aug 2018 15:08:14 +0000 (11:08 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/resolver.service.ts
Open-ILS/src/eg2/src/app/staff/common.module.ts
Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html
Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts
Open-ILS/src/eg2/src/app/staff/share/translate/translate.component.html [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/share/translate/translate.component.ts [new file with mode: 0644]

index ac5c381..faa6038 100644 (file)
@@ -3,6 +3,10 @@ import {Router, Resolve, RouterStateSnapshot,
         ActivatedRouteSnapshot} from '@angular/router';
 import {IdlService} from '@eg/core/idl.service';
 import {OrgService} from '@eg/core/org.service';
+import {LocaleService} from '@eg/core/locale.service';
+
+// For locale application
+declare var OpenSRF;
 
 @Injectable()
 export class BaseResolver implements Resolve<Promise<void>> {
@@ -11,6 +15,7 @@ export class BaseResolver implements Resolve<Promise<void>> {
         private router: Router,
         private idl: IdlService,
         private org: OrgService,
+        private locale: LocaleService
     ) {}
 
     /**
@@ -22,6 +27,8 @@ export class BaseResolver implements Resolve<Promise<void>> {
         route: ActivatedRouteSnapshot,
         state: RouterStateSnapshot): Promise<void> {
 
+        OpenSRF.locale = this.locale.currentLocaleCode();
+
         this.idl.parseIdl();
 
         return this.org.fetchOrgs(); // anonymous PCRUD.
index 6780b81..e83143c 100644 (file)
@@ -18,6 +18,7 @@ import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
 import {DateSelectComponent} from '@eg/share/date-select/date-select.component';
 import {RecordBucketDialogComponent} from '@eg/staff/share/buckets/record-bucket-dialog.component';
 import {BibSummaryComponent} from '@eg/staff/share/bib-summary/bib-summary.component';
+import {TranslateComponent} from '@eg/staff/share/translate/translate.component';
 import {AdminPageComponent} from '@eg/staff/share/admin-page/admin-page.component';
 
 /**
@@ -39,6 +40,7 @@ import {AdminPageComponent} from '@eg/staff/share/admin-page/admin-page.componen
     DateSelectComponent,
     RecordBucketDialogComponent,
     BibSummaryComponent,
+    TranslateComponent,
     AdminPageComponent
   ],
   imports: [
@@ -61,6 +63,7 @@ import {AdminPageComponent} from '@eg/staff/share/admin-page/admin-page.componen
     DateSelectComponent,
     RecordBucketDialogComponent,
     BibSummaryComponent,
+    TranslateComponent,
     AdminPageComponent
   ]
 })
index 0f76d51..289ed50 100644 (file)
 <ng-template #printTemplate let-context>Hello, {{context.world}}!</ng-template>
 
 <br/><br/>
+HERasdfE
+<div class="row">
+  <div class="col-lg-3">
+    <eg-translate #translate [idlObject]="oneBtype" fieldName="name"></eg-translate>
+    <button class="btn btn-info"
+      (click)="translate.open({size:'lg'})">Translate</button>
+  </div>
+</div>
+<br/><br/>
 
 <!-- grid stuff -->
 <ng-template #cellTmpl let-row="row" let-col="col" let-userContext="userContext">
index 9314e70..7b74516 100644 (file)
@@ -51,6 +51,8 @@ export class SandboxComponent implements OnInit {
         this.testStr = str;
     }
 
+    oneBtype: IdlObject;
+
     name = 'Jane';
 
     constructor(
@@ -101,11 +103,10 @@ export class SandboxComponent implements OnInit {
             }).pipe(map(cbt => {
                 // example of inline fleshing
                 cbt.owner(this.org.get(cbt.owner()));
+                this.oneBtype = cbt;
                 return cbt;
             }));
         };
-
-
     }
 
     btGridRowClassCallback(row: any): string {
diff --git a/Open-ILS/src/eg2/src/app/staff/share/translate/translate.component.html b/Open-ILS/src/eg2/src/app/staff/share/translate/translate.component.html
new file mode 100644 (file)
index 0000000..a57ca17
--- /dev/null
@@ -0,0 +1,51 @@
+<ng-template #dialogContent>
+  <div class="modal-header bg-info">
+    <h4 class="modal-title" i18n>
+      Translating field "{{idlClassDef.field_map[field].label}}" 
+      of "{{idlClassDef.label}}".
+    </h4>
+    <button type="button" class="close" 
+      i18n-aria-label aria-label="Close" 
+      (click)="dismiss('cross_click')">
+      <span aria-hidden="true">&times;</span>
+    </button>
+  </div>
+  <div class="modal-body form-common form-validated" *ngIf="idlObj">
+    <div class="form-group row">
+      <label class="col-lg-4 text-right font-weight-bold" 
+        i18n>Current Value</label>
+      <input 
+        type="text" 
+        [disabled]="true"
+        class="form-control col-lg-7"
+        value="{{idlObj[field]()}}">
+    </div>
+    <div class="form-group row">
+      <label class="col-lg-4 text-right font-weight-bold" 
+        i18n>Select Locale</label>
+      <select class="form-control col-lg-7" 
+        (change)="localeChanged($event)"
+        [(ngModel)]="selectedLocale">
+        <option value="{{locale.code()}}" *ngFor="let locale of locales">
+          {{locale.name()}}
+        </option>
+      </select>
+    </div>
+    <div class="form-group row">
+      <label class="col-lg-4 text-right font-weight-bold" i18n>Translation</label>
+      <input 
+        id='translation-input'
+        type="text" 
+        class="form-control col-lg-7"
+        required
+        i18n-placeholder
+        (keyup.enter)="translate()"
+        placeholder="Translation..." 
+        [(ngModel)]="translatedValue"/>
+    </div>
+  </div>
+  <div class="modal-footer">
+    <button (click)="translate()" class="btn btn-info" i18n>Apply</button>
+    <button (click)="dismiss('canceled')" class="btn btn-warning ml-2" i18n>Cancel</button>
+  </div>
+</ng-template>
diff --git a/Open-ILS/src/eg2/src/app/staff/share/translate/translate.component.ts b/Open-ILS/src/eg2/src/app/staff/share/translate/translate.component.ts
new file mode 100644 (file)
index 0000000..a165afe
--- /dev/null
@@ -0,0 +1,128 @@
+import {Component, OnInit, Input, Renderer2} from '@angular/core';
+import {IdlService, IdlObject} from '@eg/core/idl.service';
+import {ToastService} from '@eg/share/toast/toast.service';
+import {LocaleService} from '@eg/core/locale.service';
+import {AuthService} from '@eg/core/auth.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {DialogComponent} from '@eg/share/dialog/dialog.component';
+import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
+
+@Component({
+  selector: 'eg-translate',
+  templateUrl: 'translate.component.html'
+})
+
+export class TranslateComponent
+    extends DialogComponent implements OnInit {
+
+    idlClassDef: any;
+    locales: IdlObject[];
+    selectedLocale: string;
+    translatedValue: string;
+    existingTranslation: IdlObject;
+
+    idlObj: IdlObject;
+    @Input() set idlObject(o: IdlObject) {
+        if (o) {
+            this.idlObj = o;
+            this.idlClassDef = this.idl.classes[o.classname];
+            this.fetchTranslation();
+        }
+    }
+
+    field: string;
+    @Input() set fieldName(n: string) {
+        this.field = n;
+    }
+
+    constructor(
+        private modal: NgbModal, // required for passing to parent
+        private renderer: Renderer2,
+        private idl: IdlService,
+        private toast: ToastService,
+        private locale: LocaleService,
+        private pcrud: PcrudService,
+        private auth: AuthService) {
+        super(modal);
+    }
+
+    ngOnInit() {
+        // Default to the login locale
+        this.selectedLocale = this.locale.currentLocaleCode();
+        this.locales = [];
+        this.locale.supportedLocales().subscribe(l => this.locales.push(l));
+
+        this.onOpen$.subscribe(() => {
+            const elm = this.renderer.selectRootElement('#translation-input');
+            if (elm) {
+                elm.focus();
+                elm.select();
+            }
+        });
+    }
+
+    localeChanged(code: string) {
+        this.fetchTranslation();
+    }
+
+    fetchTranslation() {
+        const exist = this.existingTranslation;
+
+        if (exist
+            && exist.fq_field() === this.fqField()
+            && exist.identity_value() === this.identValue()) {
+            // Already have the current translation object.
+            return;
+        }
+
+        this.translatedValue = '';
+        this.existingTranslation = null;
+
+        this.pcrud.search('i18n', {
+            translation: this.selectedLocale, 
+            fq_field : this.fqField(), 
+            identity_value: this.identValue()
+        }).subscribe(tr => {
+            this.existingTranslation = tr;
+            this.translatedValue = tr.string();
+            console.debug('found existing translation ', tr);
+        });
+    }
+
+    fqField(): string {
+        return this.idlClassDef.classname + '.' + this.field;
+    }
+
+    identValue(): string {
+        return this.idlObj[this.idlClassDef.pkey || 'id']();
+    }
+
+    translate() {
+        if (!this.translatedValue) return;
+
+        if (this.existingTranslation) {
+            const entry = this.existingTranslation;
+            entry.string(this.translatedValue);
+
+            this.pcrud.update(entry).toPromise().then(
+                ok => this.close('Translation updated'),
+                err => console.error(err)
+            );
+
+            return;
+        }
+
+        const entry = this.idl.create('i18n');
+        entry.fq_field(this.fqField());
+        entry.identity_value(this.identValue());
+        entry.translation(this.selectedLocale);
+        entry.string(this.translatedValue);
+
+        this.pcrud.create(entry).toPromise().then(
+            ok => this.close('Translation created'),
+            err => console.error('Translation creation failed')
+        );
+    }
+}
+
+