Skip to content

Commit 529a35f

Browse files
authored
Merge pull request #4650 from crazyserver/MOBILE-4901
MOBILE-4901: Update @ngx-translate to version 17
2 parents 1e009c4 + 2da6005 commit 529a35f

File tree

13 files changed

+438
-395
lines changed

13 files changed

+438
-395
lines changed

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@
8686
"@moodlehq/cordova-plugin-statusbar": "4.0.0-moodle.5",
8787
"@moodlehq/cordova-plugin-zip": "3.1.0-moodle.1",
8888
"@moodlehq/phonegap-plugin-push": "4.0.0-moodle.13",
89-
"@ngx-translate/core": "^16.0.4",
90-
"@ngx-translate/http-loader": "^16.0.1",
89+
"@ngx-translate/core": "^17.0.0",
90+
"@ngx-translate/http-loader": "^17.0.0",
9191
"@sqlite.org/sqlite-wasm": "^3.45.0-build1",
9292
"@stylistic/eslint-plugin": "^5.4.0",
9393
"@types/cordova": "0.0.34",

src/core/base.module.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,20 @@
1414

1515
import { NgModule } from '@angular/core';
1616
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
17-
import { TranslateModule } from '@ngx-translate/core';
17+
import { TranslatePipe } from '@ngx-translate/core';
1818
import { CommonModule } from '@angular/common';
1919
import { IonicModule } from '@ionic/angular';
2020

2121
@NgModule({
2222
imports: [
23-
TranslateModule.forChild(),
23+
TranslatePipe,
2424
],
2525
exports: [
2626
CommonModule,
2727
FormsModule,
2828
IonicModule,
2929
ReactiveFormsModule,
30-
TranslateModule,
30+
TranslatePipe,
3131
],
3232
})
3333
export class CoreBaseModule {}

src/core/classes/lang-loader.ts

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
// (C) Copyright 2015 Moodle Pty Ltd.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import { Injectable } from '@angular/core';
16+
import { mergeDeep, TranslateLoader, TranslationObject } from '@ngx-translate/core';
17+
import { Http, Translate } from '@singletons';
18+
import { CoreLogger } from '@singletons/logger';
19+
import { firstValueFrom, from, Observable, of } from 'rxjs';
20+
21+
@Injectable()
22+
export class MoodleTranslateLoader implements TranslateLoader {
23+
24+
protected translations: { [lang: string]: TranslationObject } = {};
25+
26+
protected customStrings: { [lang: string]: TranslationObject } = {}; // Strings defined using the admin tool.
27+
protected sitePluginsStrings: { [lang: string]: TranslationObject } = {}; // Strings defined by site plugins.
28+
29+
static readonly PARENT_LANG_KEY = 'core.parentlanguage';
30+
31+
protected logger = CoreLogger.getInstance('MoodleTranslateLoader');
32+
33+
/**
34+
* Get the translations for a specific language.
35+
*
36+
* @param lang Language code (e.g., 'en', 'es').
37+
* @returns Observable resolved with the translations object.
38+
*/
39+
getTranslation(lang: string): Observable<TranslationObject> {
40+
if (this.translations[lang]) {
41+
this.logger.debug('Get translation', lang);
42+
// This is done here to ensure site strings and custom strings are loaded in the proper order.
43+
const translation = this.applySiteStrings(lang);
44+
45+
return of(translation);
46+
}
47+
48+
return from(this.loadLanguage(lang).then((translation) => {
49+
this.logger.debug('Successfully loaded translation', lang);
50+
51+
return translation;
52+
}).catch((error) => {
53+
this.logger.error('Error loading translation', lang, error);
54+
55+
return {};
56+
}));
57+
}
58+
59+
/**
60+
* Load translations for a specific language.
61+
*
62+
* @param lang Language code (e.g., 'en', 'es').
63+
* @returns Promise resolved with the translations object or empty object if not found.
64+
*/
65+
protected async loadLanguage(lang: string): Promise<TranslationObject> {
66+
// Return the imported translations for the requested language
67+
let translation = await this.fetchLanguageFile(lang);
68+
69+
this.translations[lang] = translation;
70+
71+
// Check if it has a parent language.
72+
const parentLang = this.getParentLanguage(lang);
73+
if (parentLang) {
74+
try {
75+
this.logger.debug('Loading parent language', parentLang);
76+
77+
// Merge parent translations with the child ones.
78+
const parentTranslations = await this.loadLanguage(parentLang);
79+
if (Object.keys(parentTranslations).length > 0) {
80+
translation = mergeDeep(parentTranslations, translation);
81+
}
82+
} catch {
83+
// Ignore errors.
84+
}
85+
}
86+
87+
this.translations[lang] = translation;
88+
89+
return this.applySiteStrings(lang);
90+
}
91+
92+
/**
93+
* Fetch the language file from assets.
94+
*
95+
* @param lang Language code.
96+
* @returns Promise resolved with the translations object.
97+
*/
98+
protected async fetchLanguageFile(lang: string): Promise<TranslationObject> {
99+
try {
100+
const request = Http.get(`/assets/lang/${lang}.json`) as Observable<TranslationObject>;
101+
102+
return await firstValueFrom(request);
103+
} catch (error) {
104+
this.logger.error('Error fetching language file', lang, error);
105+
106+
return {};
107+
}
108+
}
109+
110+
/**
111+
* Get the parent language of a certain language.
112+
* Language translation should be loaded first.
113+
*
114+
* @param lang Language code.
115+
* @returns Parent language code or undefined if not found.
116+
*/
117+
getParentLanguage(lang: string): string | undefined {
118+
const parentLang = this.translations[lang][MoodleTranslateLoader.PARENT_LANG_KEY] as string | undefined;
119+
if (parentLang && parentLang !== MoodleTranslateLoader.PARENT_LANG_KEY && parentLang !== lang) {
120+
return parentLang;
121+
}
122+
}
123+
124+
/**
125+
* Clear current custom strings.
126+
*
127+
* @param langToReload If defined, reloads the language after resetting the strings.
128+
*/
129+
async clearCustomStrings(langToReload?: string): Promise<void> {
130+
this.customStrings = {};
131+
if (!langToReload) {
132+
return;
133+
}
134+
135+
await firstValueFrom(Translate.reloadLang(langToReload));
136+
}
137+
138+
/**
139+
* Clear current site plugins strings.
140+
*
141+
* @param langToReload If defined, reloads the language after resetting the strings.
142+
*/
143+
async clearSitePluginsStrings(langToReload?: string): Promise<void> {
144+
this.sitePluginsStrings = {};
145+
146+
if (!langToReload) {
147+
return;
148+
}
149+
150+
await firstValueFrom(Translate.reloadLang(langToReload));
151+
}
152+
153+
/**
154+
* Set custom strings defined using the admin tool.
155+
*
156+
* @param strings Strings.
157+
* @param currentLang Current language. If defined, reloads the language after setting the strings.
158+
*/
159+
async setCustomStrings(strings: { [lang: string]: TranslationObject }, currentLang?: string): Promise<void> {
160+
this.customStrings = strings;
161+
162+
if (!currentLang || !strings[currentLang]) {
163+
return;
164+
}
165+
166+
// Load them in the current translations.
167+
await firstValueFrom(Translate.reloadLang(currentLang));
168+
}
169+
170+
/**
171+
* Set site plugins strings.
172+
*
173+
* @param strings Strings.
174+
* @param currentLang Current language. If defined, reloads the language after setting the strings.
175+
*/
176+
async setSitePluginsStrings(strings: { [lang: string]: TranslationObject }, currentLang?: string): Promise<void> {
177+
Object.keys(strings).forEach((lang) => {
178+
if (!this.sitePluginsStrings[lang]) {
179+
this.sitePluginsStrings[lang] = {};
180+
}
181+
182+
this.sitePluginsStrings[lang] = mergeDeep(this.sitePluginsStrings[lang], strings[lang]);
183+
});
184+
185+
if (!currentLang || !strings[currentLang]) {
186+
return;
187+
}
188+
189+
// Load them in the current translations.
190+
await firstValueFrom(Translate.reloadLang(currentLang));
191+
}
192+
193+
/**
194+
* Apply site plugins strings and custom strings to the translations.
195+
*
196+
* @param lang Language code.
197+
* @returns The merged translations object.
198+
*/
199+
protected applySiteStrings(lang: string): TranslationObject {
200+
let translation = this.translations[lang] || {};
201+
202+
const sitePluginsStrings = this.sitePluginsStrings[lang] || {};
203+
const customStrings = this.customStrings[lang] || {};
204+
const siteStrings = mergeDeep(sitePluginsStrings, customStrings);
205+
206+
// Site strings should override default ones.
207+
translation = mergeDeep(translation, siteStrings);
208+
209+
const parentLang = this.getParentLanguage(lang);
210+
if (parentLang) {
211+
const parentTranslations = this.applySiteStrings(parentLang);
212+
if (Object.keys(parentTranslations).length > 0) {
213+
// Child translations should override parent ones.
214+
translation = mergeDeep(parentTranslations, translation);
215+
}
216+
}
217+
218+
return translation;
219+
}
220+
221+
}

src/core/features/mainmenu/pages/reload/reload.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
import { Component, OnInit } from '@angular/core';
15+
import { Component } from '@angular/core';
1616
import { CoreNavigator } from '@services/navigator';
1717
import { CoreSharedModule } from '@/core/shared.module';
1818

@@ -26,12 +26,15 @@ import { CoreSharedModule } from '@/core/shared.module';
2626
CoreSharedModule,
2727
],
2828
})
29-
export default class CoreMainMenuReloadPage implements OnInit {
29+
export default class CoreMainMenuReloadPage {
3030

3131
/**
32-
* @inheritdoc
32+
* Runs when the page has fully entered and is now the active page.
33+
* This event will fire, whether it was the first load or a cached page.
34+
*
35+
* This is not done on the ngOnInit because it can happen the page is revisited before destroyed.
3336
*/
34-
ngOnInit(): void {
37+
ionViewDidEnter(): void {
3538
CoreNavigator.navigate('/main', {
3639
reset: true,
3740
});

src/core/features/siteplugins/services/siteplugins-init.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -327,11 +327,8 @@ export class CoreSitePluginsInitService {
327327
return;
328328
}
329329

330-
for (const lang in plugin.parsedLang) {
331-
const prefix = this.getPrefixForStrings(plugin.addon);
332-
333-
CoreLang.addSitePluginsStrings(lang, plugin.parsedLang[lang], prefix);
334-
}
330+
const prefix = this.getPrefixForStrings(plugin.addon);
331+
CoreLang.addSitePluginsStrings(plugin.parsedLang, prefix);
335332
}
336333

337334
/**

src/core/features/siteplugins/services/siteplugins.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { CoreSite } from '@classes/sites/site';
1919
import { CoreCourseAnyModuleData } from '@features/course/services/course';
2020
import { CoreCourses } from '@features/courses/services/courses';
2121
import { CoreFilepool } from '@services/filepool';
22-
import { CoreLang, CoreLangFormat } from '@services/lang';
22+
import { CoreLang, CoreLangFormat, CoreLangTranslationByLanguage } from '@services/lang';
2323
import { CoreSites } from '@services/sites';
2424
import { CoreText } from '@singletons/text';
2525
import { CoreUtils } from '@singletons/utils';
@@ -812,7 +812,7 @@ export type CoreSitePluginsWSPlugin = {
812812
*/
813813
export type CoreSitePluginsPlugin = CoreSitePluginsWSPlugin & {
814814
parsedHandlers?: Record<string, CoreSitePluginsHandlerData> | null;
815-
parsedLang?: Record<string, string[]> | null;
815+
parsedLang?: CoreLangTranslationByLanguage | null;
816816
};
817817

818818
/**

0 commit comments

Comments
 (0)