commit
ad81a7d9e2
|
@ -47,7 +47,7 @@
|
|||
<ion-item text-wrap *ngIf="access.canedititems && (groupInfo.separateGroups || groupInfo.visibleGroups)">
|
||||
<ion-label id="addon-feedback-groupslabel" *ngIf="groupInfo.separateGroups">{{ 'core.groupsseparate' | translate }}</ion-label>
|
||||
<ion-label id="addon-feedback-groupslabel" *ngIf="groupInfo.visibleGroups">{{ 'core.groupsvisible' | translate }}</ion-label>
|
||||
<ion-select [(ngModel)]="group" (ionChange)="setGroup(group)" aria-labelledby="addon-feedback-groupslabel">
|
||||
<ion-select [(ngModel)]="group" (ionChange)="setGroup(group)" aria-labelledby="addon-feedback-groupslabel" interface="popover">
|
||||
<ion-option *ngFor="let groupOpt of groupInfo.groups" [value]="groupOpt.id">{{groupOpt.name}}</ion-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
</ion-item>
|
||||
</ion-list>
|
||||
<ng-container *ngSwitchCase="'multichoice-d'">
|
||||
<ion-select [required]="item.required" name="{{item.typ}}_{{item.id}}" [(ngModel)]="item.value">
|
||||
<ion-select [required]="item.required" name="{{item.typ}}_{{item.id}}" [(ngModel)]="item.value" interface="popover">
|
||||
<ion-option *ngFor="let option of item.choices" [value]="option.value"><core-format-text [component]="component" [componentId]="componentId" [text]="option.label"></core-format-text></ion-option>
|
||||
</ion-select>
|
||||
</ng-container>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<ion-item text-wrap *ngIf="groupInfo.separateGroups || groupInfo.visibleGroups">
|
||||
<ion-label id="addon-feedback-groupslabel" *ngIf="groupInfo.separateGroups">{{ 'core.groupsseparate' | translate }}</ion-label>
|
||||
<ion-label id="addon-feedback-groupslabel" *ngIf="groupInfo.visibleGroups">{{ 'core.groupsvisible' | translate }}</ion-label>
|
||||
<ion-select [(ngModel)]="selectedGroup" (ionChange)="loadAttempts(selectedGroup)" aria-labelledby="addon-feedback-groupslabel">
|
||||
<ion-select [(ngModel)]="selectedGroup" (ionChange)="loadAttempts(selectedGroup)" aria-labelledby="addon-feedback-groupslabel" interface="popover">
|
||||
<ion-option *ngFor="let groupOpt of groupInfo.groups" [value]="groupOpt.id">{{groupOpt.name}}</ion-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<ion-item text-wrap *ngIf="groupInfo.separateGroups || groupInfo.visibleGroups">
|
||||
<ion-label id="addon-feedback-groupslabel" *ngIf="groupInfo.separateGroups">{{ 'core.groupsseparate' | translate }}</ion-label>
|
||||
<ion-label id="addon-feedback-groupslabel" *ngIf="groupInfo.visibleGroups">{{ 'core.groupsvisible' | translate }}</ion-label>
|
||||
<ion-select [(ngModel)]="selectedGroup" (ionChange)="loadAttempts(selectedGroup)" aria-labelledby="addon-feedback-groupslabel">
|
||||
<ion-select [(ngModel)]="selectedGroup" (ionChange)="loadAttempts(selectedGroup)" aria-labelledby="addon-feedback-groupslabel" interface="popover">
|
||||
<ion-option *ngFor="let groupOpt of groupInfo.groups" [value]="groupOpt.id">{{groupOpt.name}}</ion-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<!-- Edit. -->
|
||||
<ion-item *ngIf="edit && field && field.shortname" text-wrap [formGroup]="form">
|
||||
<ion-label stacked [core-mark-required]="field.required">{{ field.name }}</ion-label>
|
||||
<ion-select [formControlName]="field.modelName" [placeholder]="'core.choosedots' | translate" core-input-errors>
|
||||
<ion-select [formControlName]="field.modelName" [placeholder]="'core.choosedots' | translate" core-input-errors interface="popover">
|
||||
<ion-option value="">{{ 'core.choosedots' | translate }}</ion-option>
|
||||
<ion-option *ngFor="let option of field.options" [value]="option">{{option}}</ion-option>
|
||||
</ion-select>
|
||||
|
|
|
@ -18,7 +18,9 @@ import { StatusBar } from '@ionic-native/status-bar';
|
|||
import { SplashScreen } from '@ionic-native/splash-screen';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreLangProvider } from '@providers/lang';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreLoginHelperProvider } from '@core/login/providers/helper';
|
||||
|
||||
@Component({
|
||||
|
@ -33,7 +35,7 @@ export class MoodleMobileApp implements OnInit {
|
|||
|
||||
constructor(private platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen, logger: CoreLoggerProvider,
|
||||
private eventsProvider: CoreEventsProvider, private loginHelper: CoreLoginHelperProvider,
|
||||
private appProvider: CoreAppProvider) {
|
||||
private appProvider: CoreAppProvider, private langProvider: CoreLangProvider, private sitesProvider: CoreSitesProvider) {
|
||||
this.logger = logger.getInstance('AppComponent');
|
||||
|
||||
platform.ready().then(() => {
|
||||
|
@ -49,9 +51,12 @@ export class MoodleMobileApp implements OnInit {
|
|||
* Component being initialized.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
// Go to sites page when user is logged out.
|
||||
this.eventsProvider.on(CoreEventsProvider.LOGOUT, () => {
|
||||
// Go to sites page when user is logged out.
|
||||
this.appProvider.getRootNavController().setRoot('CoreLoginSitesPage');
|
||||
|
||||
// Unload lang custom strings.
|
||||
this.langProvider.clearCustomStrings();
|
||||
});
|
||||
|
||||
// Listen for session expired events.
|
||||
|
@ -111,5 +116,25 @@ export class MoodleMobileApp implements OnInit {
|
|||
this.eventsProvider.on(CoreEventsProvider.APP_LAUNCHED_URL, (url) => {
|
||||
this.loginHelper.appLaunchedByURL(url);
|
||||
});
|
||||
|
||||
// Load custom lang strings. This cannot be done inside the lang provider because it causes circular dependencies.
|
||||
const loadCustomStrings = (): void => {
|
||||
const currentSite = this.sitesProvider.getCurrentSite(),
|
||||
customStrings = currentSite && currentSite.getStoredConfig('tool_mobile_customlangstrings');
|
||||
|
||||
if (typeof customStrings != 'undefined') {
|
||||
this.langProvider.loadCustomStrings(customStrings);
|
||||
}
|
||||
};
|
||||
|
||||
this.eventsProvider.on(CoreEventsProvider.LOGIN, () => {
|
||||
loadCustomStrings();
|
||||
});
|
||||
|
||||
this.eventsProvider.on(CoreEventsProvider.SITE_UPDATED, (siteId) => {
|
||||
if (siteId == this.sitesProvider.getCurrentSiteId()) {
|
||||
loadCustomStrings();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<ion-content>
|
||||
<ion-item text-wrap>
|
||||
<ion-label><h2>{{ 'core.settings.language' | translate }}</h2></ion-label>
|
||||
<ion-select [(ngModel)]="selectedLanguage" (ngModelChange)="languageChanged()">
|
||||
<ion-select [(ngModel)]="selectedLanguage" (ngModelChange)="languageChanged()" interface="popover">
|
||||
<ion-option *ngFor="let code of languageCodes" [value]="code">{{ languages[code] }}</ion-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
|
|
@ -53,13 +53,10 @@ export class CoreLangProvider {
|
|||
* @param {string} [prefix] A prefix to add to all keys.
|
||||
*/
|
||||
addSitePluginsStrings(lang: string, strings: any, prefix?: string): void {
|
||||
// Initialize structures if they don't exist.
|
||||
// Initialize structure if it doesn't exist.
|
||||
if (!this.sitePluginsStrings[lang]) {
|
||||
this.sitePluginsStrings[lang] = {};
|
||||
}
|
||||
if (!this.translate.translations[lang]) {
|
||||
this.translate.translations[lang] = {};
|
||||
}
|
||||
|
||||
for (const key in strings) {
|
||||
const prefixedKey = prefix + key;
|
||||
|
@ -75,19 +72,8 @@ export class CoreLangProvider {
|
|||
// Make sure we didn't add to many brackets in some case.
|
||||
value = value.replace(/{{{([^ ]+)}}}/gm, '{{$1}}');
|
||||
|
||||
if (!this.sitePluginsStrings[lang][prefixedKey]) {
|
||||
// It's a new site plugin string. Store the original value.
|
||||
this.sitePluginsStrings[lang][prefixedKey] = {
|
||||
original: this.translate.translations[lang][prefixedKey],
|
||||
value: value
|
||||
};
|
||||
} else {
|
||||
// Site plugin string already defined. Store the new value.
|
||||
this.sitePluginsStrings[lang][prefixedKey].value = value;
|
||||
}
|
||||
|
||||
// Store the string in the translations table.
|
||||
this.translate.translations[lang][prefixedKey] = value;
|
||||
// Load the string.
|
||||
this.loadString(this.sitePluginsStrings, lang, prefixedKey, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,13 +86,38 @@ export class CoreLangProvider {
|
|||
changeCurrentLanguage(language: string): Promise<any> {
|
||||
const promises = [];
|
||||
|
||||
promises.push(this.translate.use(language));
|
||||
// Change the language, resolving the promise when we receive the first value.
|
||||
promises.push(new Promise((resolve, reject): void => {
|
||||
const subscription = this.translate.use(language).subscribe((data) => {
|
||||
resolve(data);
|
||||
|
||||
// Data received, unsubscribe. Use a timeout because we can receive a value immediately.
|
||||
setTimeout(() => {
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
}, (error) => {
|
||||
reject(error);
|
||||
|
||||
// Error received, unsubscribe. Use a timeout because we can receive a value immediately.
|
||||
setTimeout(() => {
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
// Change the config.
|
||||
promises.push(this.configProvider.set('current_language', language));
|
||||
|
||||
moment.locale(language);
|
||||
this.currentLanguage = language;
|
||||
|
||||
return Promise.all(promises);
|
||||
return Promise.all(promises).finally(() => {
|
||||
// Load the custom and site plugins strings for the language.
|
||||
if (this.loadLangStrings(this.customStrings, language) || this.loadLangStrings(this.sitePluginsStrings, language)) {
|
||||
// Some lang strings have changed, emit an event to update the pipes.
|
||||
this.translate.onLangChange.emit({lang: language, translations: this.translate.translations[language]});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -227,15 +238,75 @@ export class CoreLangProvider {
|
|||
this.customStrings[lang] = {};
|
||||
}
|
||||
|
||||
// Store the original value of the custom string.
|
||||
this.customStrings[lang][values[0]] = {
|
||||
original: this.translate.translations[lang][values[0]],
|
||||
value: values[1]
|
||||
// Convert old keys format to new one.
|
||||
const key = values[0].replace(/^mm\.core/, 'core').replace(/^mm\./, 'core.').replace(/^mma\./, 'addon.')
|
||||
.replace(/^core\.sidemenu/, 'core.mainmenu').replace(/^addon\.grades/, 'core.grades')
|
||||
.replace(/^addon\.participants/, 'core.user');
|
||||
|
||||
this.loadString(this.customStrings, lang, key, values[1]);
|
||||
});
|
||||
|
||||
this.customStringsRaw = strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load custom strings for a certain language that weren't loaded because the language wasn't active.
|
||||
*
|
||||
* @param {any} langObject The object with the strings to load.
|
||||
* @param {string} lang Language to load.
|
||||
* @return {boolean} Whether the translation table was modified.
|
||||
*/
|
||||
loadLangStrings(langObject: any, lang: string): boolean {
|
||||
let langApplied = false;
|
||||
|
||||
if (langObject[lang]) {
|
||||
for (const key in langObject[lang]) {
|
||||
const entry = langObject[lang][key];
|
||||
|
||||
if (!entry.applied) {
|
||||
// Store the original value of the string.
|
||||
entry.original = this.translate.translations[lang][key];
|
||||
|
||||
// Store the string in the translations table.
|
||||
this.translate.translations[lang][key] = entry.value;
|
||||
|
||||
entry.applied = true;
|
||||
langApplied = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return langApplied;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a string in a certain lang object and in the translate table if the lang is loaded.
|
||||
*
|
||||
* @param {any} langObject The object where to store the lang.
|
||||
* @param {string} lang Language code.
|
||||
* @param {string} key String key.
|
||||
* @param {string} value String value.
|
||||
*/
|
||||
loadString(langObject: any, lang: string, key: string, value: string): void {
|
||||
if (this.translate.translations[lang]) {
|
||||
// The language is loaded.
|
||||
// Store the original value of the string.
|
||||
langObject[lang][key] = {
|
||||
original: this.translate.translations[lang][key],
|
||||
value: value,
|
||||
applied: true
|
||||
};
|
||||
|
||||
// Store the string in the translations table.
|
||||
this.translate.translations[lang][values[0]] = values[1];
|
||||
});
|
||||
this.translate.translations[lang][key] = value;
|
||||
} else {
|
||||
// The language isn't loaded.
|
||||
// Save it in our object but not in the translations table, it will be loaded when the lang is loaded.
|
||||
langObject[lang][key] = {
|
||||
value: value,
|
||||
applied: false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -246,6 +317,11 @@ export class CoreLangProvider {
|
|||
protected unloadStrings(strings: any): void {
|
||||
// Iterate over all languages and strings.
|
||||
for (const lang in strings) {
|
||||
if (!this.translate.translations[lang]) {
|
||||
// Language isn't loaded, nothing to unload.
|
||||
continue;
|
||||
}
|
||||
|
||||
const langStrings = strings[lang];
|
||||
for (const key in langStrings) {
|
||||
const entry = langStrings[key];
|
||||
|
|
Loading…
Reference in New Issue