From: Chocobozzz Date: Wed, 6 Jun 2018 15:37:13 +0000 (+0200) Subject: Little i18n refractoring X-Git-Tag: v1.0.0-beta.8~37 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=74b7c6d48e9ca377fe938c8134ed74b612e62ba0;p=oweals%2Fpeertube.git Little i18n refractoring --- diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index e60a74cc0..51e354378 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts @@ -16,8 +16,8 @@ import { MenuComponent } from './menu' import { SharedModule } from './shared' import { SignupModule } from './signup' import { VideosModule } from './videos' -import { buildFileLocale, getDefaultLocale } from '../../../shared/models/i18n' -import { environment } from '../environments/environment' +import { buildFileLocale, getCompleteLocale, getDefaultLocale, isDefaultLocale } from '../../../shared/models/i18n' +import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils' export function metaFactory (serverService: ServerService): MetaLoader { return new MetaStaticLoader({ @@ -67,17 +67,17 @@ export function metaFactory (serverService: ServerService): MetaLoader { { provide: TRANSLATIONS, useFactory: (locale) => { - // On dev mode, test locales - if (environment.production === false && window.location.search === '?lang=fr') { - return require(`raw-loader!../locale/target/angular_fr.xml`) + // On dev mode, test localization + if (isOnDevLocale()) { + locale = getDevLocale() + return require(`raw-loader!../locale/target/angular_${locale}.xml`) } - const fileLocale = buildFileLocale(locale) - // Default locale, nothing to translate - const defaultFileLocale = buildFileLocale(getDefaultLocale()) - if (fileLocale === defaultFileLocale) return '' + const completeLocale = getCompleteLocale(locale) + if (isDefaultLocale(completeLocale)) return '' + const fileLocale = buildFileLocale(locale) return require(`raw-loader!../locale/target/angular_${fileLocale}.xml`) }, deps: [ LOCALE_ID ] diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts index 56d33339e..74363e6a1 100644 --- a/client/src/app/core/server/server.service.ts +++ b/client/src/app/core/server/server.service.ts @@ -2,13 +2,13 @@ import { map, share, switchMap, tap } from 'rxjs/operators' import { HttpClient } from '@angular/common/http' import { Inject, Injectable, LOCALE_ID } from '@angular/core' import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' -import { Observable, ReplaySubject } from 'rxjs' -import { ServerConfig } from '../../../../../shared' +import { Observable, ReplaySubject, of } from 'rxjs' +import { getCompleteLocale, ServerConfig } from '../../../../../shared' import { About } from '../../../../../shared/models/server/about.model' import { environment } from '../../../environments/environment' import { VideoConstant, VideoPrivacy } from '../../../../../shared/models/videos' -import { buildFileLocale, getDefaultLocale } from '../../../../../shared/models/i18n' -import { peertubeTranslate } from '@app/shared/i18n/i18n-utils' +import { isDefaultLocale } from '../../../../../shared/models/i18n' +import { getDevLocale, isOnDevLocale, peertubeTranslate } from '@app/shared/i18n/i18n-utils' @Injectable() export class ServerService { @@ -72,8 +72,8 @@ export class ServerService { private http: HttpClient, @Inject(LOCALE_ID) private localeId: string ) { - this.loadConfigLocally() this.loadServerLocale() + this.loadConfigLocally() } loadConfig () { @@ -163,14 +163,16 @@ export class ServerService { } private loadServerLocale () { - const fileLocale = buildFileLocale(environment.production === true ? this.localeId : 'fr') + const completeLocale = isOnDevLocale() ? getDevLocale() : getCompleteLocale(this.localeId) // Default locale, nothing to translate - const defaultFileLocale = buildFileLocale(getDefaultLocale()) - if (fileLocale === defaultFileLocale) return {} + if (isDefaultLocale(completeLocale)) { + this.localeObservable = of({}).pipe(share()) + return + } this.localeObservable = this.http - .get(ServerService.BASE_LOCALE_URL + fileLocale + '/server.json') + .get(ServerService.BASE_LOCALE_URL + completeLocale + '/server.json') .pipe(share()) } diff --git a/client/src/app/shared/i18n/i18n-utils.ts b/client/src/app/shared/i18n/i18n-utils.ts index c1de51b7b..37180b930 100644 --- a/client/src/app/shared/i18n/i18n-utils.ts +++ b/client/src/app/shared/i18n/i18n-utils.ts @@ -1,7 +1,19 @@ +import { environment } from '../../../environments/environment' + function peertubeTranslate (str: string, translations: { [ id: string ]: string }) { return translations[str] ? translations[str] : str } +function isOnDevLocale () { + return environment.production === false && window.location.search === '?lang=fr' +} + +function getDevLocale () { + return 'fr' +} + export { + getDevLocale, + isOnDevLocale, peertubeTranslate } diff --git a/client/src/app/shared/video/video.service.ts b/client/src/app/shared/video/video.service.ts index c607b7d6a..58cb52efc 100644 --- a/client/src/app/shared/video/video.service.ts +++ b/client/src/app/shared/video/video.service.ts @@ -46,8 +46,8 @@ export class VideoService { return this.serverService.localeObservable .pipe( switchMap(translations => { - return this.authHttp.get(VideoService.BASE_VIDEO_URL + uuid) - .pipe(map(videoHash => ({ videoHash, translations }))) + return this.authHttp.get(VideoService.BASE_VIDEO_URL + uuid) + .pipe(map(videoHash => ({ videoHash, translations }))) }), map(({ videoHash, translations }) => new VideoDetails(videoHash, translations)), catchError(res => this.restExtractor.handleError(res)) diff --git a/client/src/app/videos/+video-watch/video-watch.component.ts b/client/src/app/videos/+video-watch/video-watch.component.ts index d3e16c4cf..4a67d456e 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts @@ -25,6 +25,7 @@ import { getVideojsOptions, loadLocale, addContextMenu } from '../../../assets/p import { ServerService } from '@app/core' import { I18n } from '@ngx-translate/i18n-polyfill' import { environment } from '../../../environments/environment' +import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils' @Component({ selector: 'my-video-watch', @@ -377,7 +378,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { }) if (this.videojsLocaleLoaded === false) { - await loadLocale(environment.apiUrl, videojs, environment.production === true ? this.localeId : 'fr') + await loadLocale(environment.apiUrl, videojs, isOnDevLocale() ? getDevLocale() : this.localeId) this.videojsLocaleLoaded = true } diff --git a/client/src/assets/player/peertube-player.ts b/client/src/assets/player/peertube-player.ts index b604097fa..9e37b75d2 100644 --- a/client/src/assets/player/peertube-player.ts +++ b/client/src/assets/player/peertube-player.ts @@ -12,7 +12,7 @@ import './peertube-videojs-plugin' import './peertube-load-progress-bar' import { videojsUntyped } from './peertube-videojs-typings' import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils' -import { is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n' +import { getCompleteLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n' // Change 'Playback Rate' to 'Speed' (smaller for our settings menu) videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed' @@ -141,11 +141,13 @@ function addContextMenu (player: any, videoEmbedUrl: string) { } function loadLocale (serverUrl: string, videojs: any, locale: string) { - if (!is18nLocale(locale) || isDefaultLocale(locale)) return undefined + const completeLocale = getCompleteLocale(locale) - return fetch(serverUrl + '/client/locales/' + locale + '/player.json') + if (!is18nLocale(completeLocale) || isDefaultLocale(completeLocale)) return Promise.resolve(undefined) + + return fetch(serverUrl + '/client/locales/' + completeLocale + '/player.json') .then(res => res.json()) - .then(json => videojs.addLanguage(locale, json)) + .then(json => videojs.addLanguage(completeLocale, json)) } export { diff --git a/client/src/main.ts b/client/src/main.ts index 19f45a3e3..061be17de 100644 --- a/client/src/main.ts +++ b/client/src/main.ts @@ -5,14 +5,17 @@ import { AppModule } from './app/app.module' import { environment } from './environments/environment' import { hmrBootstrap } from './hmr' +import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils' let providers = [] if (environment.production) { enableProdMode() } -if (environment.production === false && window.location.search === '?lang=fr') { - const translations = require(`raw-loader!./locale/target/angular_fr.xml`) +// Template translation, should be in the bootstrap step +if (isOnDevLocale()) { + const locale = getDevLocale() + const translations = require(`raw-loader!./locale/target/angular_${locale}.xml`) providers = [ { provide: TRANSLATIONS, useValue: translations }, diff --git a/scripts/i18n/xliff2json.ts b/scripts/i18n/xliff2json.ts index fa5a71d65..c60739561 100755 --- a/scripts/i18n/xliff2json.ts +++ b/scripts/i18n/xliff2json.ts @@ -1,7 +1,7 @@ import * as xliff12ToJs from 'xliff/xliff12ToJs' import { unlink, readFileSync, writeFile } from 'fs' import { join } from 'path' -import { buildFileLocale, I18N_LOCALES, isDefaultLocale } from '../../shared/models/i18n/i18n' +import { buildFileLocale, I18N_LOCALES, isDefaultLocale, LOCALE_FILES } from '../../shared/models/i18n/i18n' import { eachSeries } from 'async' const sources: string[] = [] @@ -9,7 +9,7 @@ const availableLocales = Object.keys(I18N_LOCALES) .filter(l => isDefaultLocale(l) === false) .map(l => buildFileLocale(l)) -for (const file of [ 'server', 'player' ]) { +for (const file of LOCALE_FILES) { for (const locale of availableLocales) { sources.push(join(__dirname, '../../../client/src/locale/target/', `${file}_${locale}.xml`)) } diff --git a/server/controllers/client.ts b/server/controllers/client.ts index ec78a4bbc..385757fa6 100644 --- a/server/controllers/client.ts +++ b/server/controllers/client.ts @@ -3,18 +3,12 @@ import * as express from 'express' import { join } from 'path' import * as validator from 'validator' import { escapeHTML, readFileBufferPromise, root } from '../helpers/core-utils' -import { - ACCEPT_HEADERS, - CONFIG, - EMBED_SIZE, - OPENGRAPH_AND_OEMBED_COMMENT, - STATIC_MAX_AGE, - STATIC_PATHS -} from '../initializers' +import { ACCEPT_HEADERS, CONFIG, EMBED_SIZE, OPENGRAPH_AND_OEMBED_COMMENT, STATIC_MAX_AGE, STATIC_PATHS } from '../initializers' import { asyncMiddleware } from '../middlewares' import { VideoModel } from '../models/video/video' import { VideoPrivacy } from '../../shared/models/videos' -import { I18N_LOCALES, is18nLocale, getDefaultLocale } from '../../shared/models' +import { buildFileLocale, getCompleteLocale, getDefaultLocale, is18nLocale } from '../../shared/models' +import { LOCALE_FILES } from '../../shared/models/i18n/i18n' const clientsRouter = express.Router() @@ -51,8 +45,10 @@ clientsRouter.use('/client/locales/:locale/:file.json', function (req, res) { const locale = req.params.locale const file = req.params.file - if (is18nLocale(locale) && [ 'player', 'server' ].indexOf(file) !== -1) { - return res.sendFile(join(__dirname, `../../../client/dist/locale/${file}_${locale}.json`)) + if (is18nLocale(locale) && LOCALE_FILES.indexOf(file) !== -1) { + const completeLocale = getCompleteLocale(locale) + const completeFileLocale = buildFileLocale(completeLocale) + return res.sendFile(join(__dirname, `../../../client/dist/locale/${file}_${completeFileLocale}.json`)) } return res.sendStatus(404) @@ -88,12 +84,12 @@ function getIndexPath (req: express.Request, paramLang?: string) { if (paramLang && is18nLocale(paramLang)) { lang = paramLang } else { - // lang = req.acceptsLanguages(Object.keys(I18N_LOCALES)) || getDefaultLocale() + // lang = req.acceptsLanguages(POSSIBLE_LOCALES) || getDefaultLocale() // Disable auto language for now lang = getDefaultLocale() } - return join(__dirname, '../../../client/dist/' + lang + '/index.html') + return join(__dirname, '../../../client/dist/' + buildFileLocale(lang) + '/index.html') } function addOpenGraphAndOEmbedTags (htmlStringPage: string, video: VideoModel) { diff --git a/shared/models/i18n/i18n.ts b/shared/models/i18n/i18n.ts index 4d50bc36e..be1420150 100644 --- a/shared/models/i18n/i18n.ts +++ b/shared/models/i18n/i18n.ts @@ -1,34 +1,45 @@ +export const LOCALE_FILES = [ 'player', 'server' ] + export const I18N_LOCALES = { 'en-US': 'English (US)', fr: 'French' } +const I18N_LOCALE_ALIAS = { + 'en': 'en-US' +} + +export const POSSIBLE_LOCALES = Object.keys(I18N_LOCALES) + .concat(Object.keys(I18N_LOCALE_ALIAS)) + +const possiblePaths = POSSIBLE_LOCALES.map(l => '/' + l) + export function getDefaultLocale () { return 'en-US' } export function isDefaultLocale (locale: string) { - return locale === getDefaultLocale() + return getCompleteLocale(locale) === getCompleteLocale(getDefaultLocale()) } -const possiblePaths = Object.keys(I18N_LOCALES).map(l => '/' + l) export function is18nPath (path: string) { return possiblePaths.indexOf(path) !== -1 } -const possibleLanguages = Object.keys(I18N_LOCALES) export function is18nLocale (locale: string) { - return possibleLanguages.indexOf(locale) !== -1 + return POSSIBLE_LOCALES.indexOf(locale) !== -1 +} + +export function getCompleteLocale (locale: string) { + if (!locale) return locale + + if (I18N_LOCALE_ALIAS[locale]) return I18N_LOCALE_ALIAS[locale] + + return locale } -// Only use in dev mode, so relax -// In production, the locale always match with a I18N_LANGUAGES key export function buildFileLocale (locale: string) { - if (!is18nLocale(locale)) { - // Some working examples for development purpose - if (locale.split('-')[ 0 ] === 'en') return 'en_US' - else if (locale === 'fr') return 'fr' - } + const completeLocale = getCompleteLocale(locale) - return locale.replace('-', '_') + return completeLocale.replace('-', '_') }