Little i18n refractoring
This commit is contained in:
parent
7ce44a74a3
commit
74b7c6d48e
|
@ -16,8 +16,8 @@ import { MenuComponent } from './menu'
|
||||||
import { SharedModule } from './shared'
|
import { SharedModule } from './shared'
|
||||||
import { SignupModule } from './signup'
|
import { SignupModule } from './signup'
|
||||||
import { VideosModule } from './videos'
|
import { VideosModule } from './videos'
|
||||||
import { buildFileLocale, getDefaultLocale } from '../../../shared/models/i18n'
|
import { buildFileLocale, getCompleteLocale, getDefaultLocale, isDefaultLocale } from '../../../shared/models/i18n'
|
||||||
import { environment } from '../environments/environment'
|
import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils'
|
||||||
|
|
||||||
export function metaFactory (serverService: ServerService): MetaLoader {
|
export function metaFactory (serverService: ServerService): MetaLoader {
|
||||||
return new MetaStaticLoader({
|
return new MetaStaticLoader({
|
||||||
|
@ -67,17 +67,17 @@ export function metaFactory (serverService: ServerService): MetaLoader {
|
||||||
{
|
{
|
||||||
provide: TRANSLATIONS,
|
provide: TRANSLATIONS,
|
||||||
useFactory: (locale) => {
|
useFactory: (locale) => {
|
||||||
// On dev mode, test locales
|
// On dev mode, test localization
|
||||||
if (environment.production === false && window.location.search === '?lang=fr') {
|
if (isOnDevLocale()) {
|
||||||
return require(`raw-loader!../locale/target/angular_fr.xml`)
|
locale = getDevLocale()
|
||||||
|
return require(`raw-loader!../locale/target/angular_${locale}.xml`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileLocale = buildFileLocale(locale)
|
|
||||||
|
|
||||||
// Default locale, nothing to translate
|
// Default locale, nothing to translate
|
||||||
const defaultFileLocale = buildFileLocale(getDefaultLocale())
|
const completeLocale = getCompleteLocale(locale)
|
||||||
if (fileLocale === defaultFileLocale) return ''
|
if (isDefaultLocale(completeLocale)) return ''
|
||||||
|
|
||||||
|
const fileLocale = buildFileLocale(locale)
|
||||||
return require(`raw-loader!../locale/target/angular_${fileLocale}.xml`)
|
return require(`raw-loader!../locale/target/angular_${fileLocale}.xml`)
|
||||||
},
|
},
|
||||||
deps: [ LOCALE_ID ]
|
deps: [ LOCALE_ID ]
|
||||||
|
|
|
@ -2,13 +2,13 @@ import { map, share, switchMap, tap } from 'rxjs/operators'
|
||||||
import { HttpClient } from '@angular/common/http'
|
import { HttpClient } from '@angular/common/http'
|
||||||
import { Inject, Injectable, LOCALE_ID } from '@angular/core'
|
import { Inject, Injectable, LOCALE_ID } from '@angular/core'
|
||||||
import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
|
import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
|
||||||
import { Observable, ReplaySubject } from 'rxjs'
|
import { Observable, ReplaySubject, of } from 'rxjs'
|
||||||
import { ServerConfig } from '../../../../../shared'
|
import { getCompleteLocale, ServerConfig } from '../../../../../shared'
|
||||||
import { About } from '../../../../../shared/models/server/about.model'
|
import { About } from '../../../../../shared/models/server/about.model'
|
||||||
import { environment } from '../../../environments/environment'
|
import { environment } from '../../../environments/environment'
|
||||||
import { VideoConstant, VideoPrivacy } from '../../../../../shared/models/videos'
|
import { VideoConstant, VideoPrivacy } from '../../../../../shared/models/videos'
|
||||||
import { buildFileLocale, getDefaultLocale } from '../../../../../shared/models/i18n'
|
import { isDefaultLocale } from '../../../../../shared/models/i18n'
|
||||||
import { peertubeTranslate } from '@app/shared/i18n/i18n-utils'
|
import { getDevLocale, isOnDevLocale, peertubeTranslate } from '@app/shared/i18n/i18n-utils'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ServerService {
|
export class ServerService {
|
||||||
|
@ -72,8 +72,8 @@ export class ServerService {
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
@Inject(LOCALE_ID) private localeId: string
|
@Inject(LOCALE_ID) private localeId: string
|
||||||
) {
|
) {
|
||||||
this.loadConfigLocally()
|
|
||||||
this.loadServerLocale()
|
this.loadServerLocale()
|
||||||
|
this.loadConfigLocally()
|
||||||
}
|
}
|
||||||
|
|
||||||
loadConfig () {
|
loadConfig () {
|
||||||
|
@ -163,14 +163,16 @@ export class ServerService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadServerLocale () {
|
private loadServerLocale () {
|
||||||
const fileLocale = buildFileLocale(environment.production === true ? this.localeId : 'fr')
|
const completeLocale = isOnDevLocale() ? getDevLocale() : getCompleteLocale(this.localeId)
|
||||||
|
|
||||||
// Default locale, nothing to translate
|
// Default locale, nothing to translate
|
||||||
const defaultFileLocale = buildFileLocale(getDefaultLocale())
|
if (isDefaultLocale(completeLocale)) {
|
||||||
if (fileLocale === defaultFileLocale) return {}
|
this.localeObservable = of({}).pipe(share())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this.localeObservable = this.http
|
this.localeObservable = this.http
|
||||||
.get(ServerService.BASE_LOCALE_URL + fileLocale + '/server.json')
|
.get(ServerService.BASE_LOCALE_URL + completeLocale + '/server.json')
|
||||||
.pipe(share())
|
.pipe(share())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,19 @@
|
||||||
|
import { environment } from '../../../environments/environment'
|
||||||
|
|
||||||
function peertubeTranslate (str: string, translations: { [ id: string ]: string }) {
|
function peertubeTranslate (str: string, translations: { [ id: string ]: string }) {
|
||||||
return translations[str] ? translations[str] : str
|
return translations[str] ? translations[str] : str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isOnDevLocale () {
|
||||||
|
return environment.production === false && window.location.search === '?lang=fr'
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDevLocale () {
|
||||||
|
return 'fr'
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
getDevLocale,
|
||||||
|
isOnDevLocale,
|
||||||
peertubeTranslate
|
peertubeTranslate
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,8 +46,8 @@ export class VideoService {
|
||||||
return this.serverService.localeObservable
|
return this.serverService.localeObservable
|
||||||
.pipe(
|
.pipe(
|
||||||
switchMap(translations => {
|
switchMap(translations => {
|
||||||
return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid)
|
return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid)
|
||||||
.pipe(map(videoHash => ({ videoHash, translations })))
|
.pipe(map(videoHash => ({ videoHash, translations })))
|
||||||
}),
|
}),
|
||||||
map(({ videoHash, translations }) => new VideoDetails(videoHash, translations)),
|
map(({ videoHash, translations }) => new VideoDetails(videoHash, translations)),
|
||||||
catchError(res => this.restExtractor.handleError(res))
|
catchError(res => this.restExtractor.handleError(res))
|
||||||
|
|
|
@ -25,6 +25,7 @@ import { getVideojsOptions, loadLocale, addContextMenu } from '../../../assets/p
|
||||||
import { ServerService } from '@app/core'
|
import { ServerService } from '@app/core'
|
||||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
import { environment } from '../../../environments/environment'
|
import { environment } from '../../../environments/environment'
|
||||||
|
import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-video-watch',
|
selector: 'my-video-watch',
|
||||||
|
@ -377,7 +378,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.videojsLocaleLoaded === false) {
|
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
|
this.videojsLocaleLoaded = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import './peertube-videojs-plugin'
|
||||||
import './peertube-load-progress-bar'
|
import './peertube-load-progress-bar'
|
||||||
import { videojsUntyped } from './peertube-videojs-typings'
|
import { videojsUntyped } from './peertube-videojs-typings'
|
||||||
import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils'
|
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)
|
// Change 'Playback Rate' to 'Speed' (smaller for our settings menu)
|
||||||
videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed'
|
videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed'
|
||||||
|
@ -141,11 +141,13 @@ function addContextMenu (player: any, videoEmbedUrl: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadLocale (serverUrl: string, videojs: any, locale: 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(res => res.json())
|
||||||
.then(json => videojs.addLanguage(locale, json))
|
.then(json => videojs.addLanguage(completeLocale, json))
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|
|
@ -5,14 +5,17 @@ import { AppModule } from './app/app.module'
|
||||||
import { environment } from './environments/environment'
|
import { environment } from './environments/environment'
|
||||||
|
|
||||||
import { hmrBootstrap } from './hmr'
|
import { hmrBootstrap } from './hmr'
|
||||||
|
import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils'
|
||||||
|
|
||||||
let providers = []
|
let providers = []
|
||||||
if (environment.production) {
|
if (environment.production) {
|
||||||
enableProdMode()
|
enableProdMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (environment.production === false && window.location.search === '?lang=fr') {
|
// Template translation, should be in the bootstrap step
|
||||||
const translations = require(`raw-loader!./locale/target/angular_fr.xml`)
|
if (isOnDevLocale()) {
|
||||||
|
const locale = getDevLocale()
|
||||||
|
const translations = require(`raw-loader!./locale/target/angular_${locale}.xml`)
|
||||||
|
|
||||||
providers = [
|
providers = [
|
||||||
{ provide: TRANSLATIONS, useValue: translations },
|
{ provide: TRANSLATIONS, useValue: translations },
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as xliff12ToJs from 'xliff/xliff12ToJs'
|
import * as xliff12ToJs from 'xliff/xliff12ToJs'
|
||||||
import { unlink, readFileSync, writeFile } from 'fs'
|
import { unlink, readFileSync, writeFile } from 'fs'
|
||||||
import { join } from 'path'
|
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'
|
import { eachSeries } from 'async'
|
||||||
|
|
||||||
const sources: string[] = []
|
const sources: string[] = []
|
||||||
|
@ -9,7 +9,7 @@ const availableLocales = Object.keys(I18N_LOCALES)
|
||||||
.filter(l => isDefaultLocale(l) === false)
|
.filter(l => isDefaultLocale(l) === false)
|
||||||
.map(l => buildFileLocale(l))
|
.map(l => buildFileLocale(l))
|
||||||
|
|
||||||
for (const file of [ 'server', 'player' ]) {
|
for (const file of LOCALE_FILES) {
|
||||||
for (const locale of availableLocales) {
|
for (const locale of availableLocales) {
|
||||||
sources.push(join(__dirname, '../../../client/src/locale/target/', `${file}_${locale}.xml`))
|
sources.push(join(__dirname, '../../../client/src/locale/target/', `${file}_${locale}.xml`))
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,18 +3,12 @@ import * as express from 'express'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import * as validator from 'validator'
|
import * as validator from 'validator'
|
||||||
import { escapeHTML, readFileBufferPromise, root } from '../helpers/core-utils'
|
import { escapeHTML, readFileBufferPromise, root } from '../helpers/core-utils'
|
||||||
import {
|
import { ACCEPT_HEADERS, CONFIG, EMBED_SIZE, OPENGRAPH_AND_OEMBED_COMMENT, STATIC_MAX_AGE, STATIC_PATHS } from '../initializers'
|
||||||
ACCEPT_HEADERS,
|
|
||||||
CONFIG,
|
|
||||||
EMBED_SIZE,
|
|
||||||
OPENGRAPH_AND_OEMBED_COMMENT,
|
|
||||||
STATIC_MAX_AGE,
|
|
||||||
STATIC_PATHS
|
|
||||||
} from '../initializers'
|
|
||||||
import { asyncMiddleware } from '../middlewares'
|
import { asyncMiddleware } from '../middlewares'
|
||||||
import { VideoModel } from '../models/video/video'
|
import { VideoModel } from '../models/video/video'
|
||||||
import { VideoPrivacy } from '../../shared/models/videos'
|
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()
|
const clientsRouter = express.Router()
|
||||||
|
|
||||||
|
@ -51,8 +45,10 @@ clientsRouter.use('/client/locales/:locale/:file.json', function (req, res) {
|
||||||
const locale = req.params.locale
|
const locale = req.params.locale
|
||||||
const file = req.params.file
|
const file = req.params.file
|
||||||
|
|
||||||
if (is18nLocale(locale) && [ 'player', 'server' ].indexOf(file) !== -1) {
|
if (is18nLocale(locale) && LOCALE_FILES.indexOf(file) !== -1) {
|
||||||
return res.sendFile(join(__dirname, `../../../client/dist/locale/${file}_${locale}.json`))
|
const completeLocale = getCompleteLocale(locale)
|
||||||
|
const completeFileLocale = buildFileLocale(completeLocale)
|
||||||
|
return res.sendFile(join(__dirname, `../../../client/dist/locale/${file}_${completeFileLocale}.json`))
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.sendStatus(404)
|
return res.sendStatus(404)
|
||||||
|
@ -88,12 +84,12 @@ function getIndexPath (req: express.Request, paramLang?: string) {
|
||||||
if (paramLang && is18nLocale(paramLang)) {
|
if (paramLang && is18nLocale(paramLang)) {
|
||||||
lang = paramLang
|
lang = paramLang
|
||||||
} else {
|
} else {
|
||||||
// lang = req.acceptsLanguages(Object.keys(I18N_LOCALES)) || getDefaultLocale()
|
// lang = req.acceptsLanguages(POSSIBLE_LOCALES) || getDefaultLocale()
|
||||||
// Disable auto language for now
|
// Disable auto language for now
|
||||||
lang = getDefaultLocale()
|
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) {
|
function addOpenGraphAndOEmbedTags (htmlStringPage: string, video: VideoModel) {
|
||||||
|
|
|
@ -1,34 +1,45 @@
|
||||||
|
export const LOCALE_FILES = [ 'player', 'server' ]
|
||||||
|
|
||||||
export const I18N_LOCALES = {
|
export const I18N_LOCALES = {
|
||||||
'en-US': 'English (US)',
|
'en-US': 'English (US)',
|
||||||
fr: 'French'
|
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 () {
|
export function getDefaultLocale () {
|
||||||
return 'en-US'
|
return 'en-US'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isDefaultLocale (locale: string) {
|
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) {
|
export function is18nPath (path: string) {
|
||||||
return possiblePaths.indexOf(path) !== -1
|
return possiblePaths.indexOf(path) !== -1
|
||||||
}
|
}
|
||||||
|
|
||||||
const possibleLanguages = Object.keys(I18N_LOCALES)
|
|
||||||
export function is18nLocale (locale: string) {
|
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) {
|
export function buildFileLocale (locale: string) {
|
||||||
if (!is18nLocale(locale)) {
|
const completeLocale = getCompleteLocale(locale)
|
||||||
// Some working examples for development purpose
|
|
||||||
if (locale.split('-')[ 0 ] === 'en') return 'en_US'
|
|
||||||
else if (locale === 'fr') return 'fr'
|
|
||||||
}
|
|
||||||
|
|
||||||
return locale.replace('-', '_')
|
return completeLocale.replace('-', '_')
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue