import { catchError } from 'rxjs/operators'
-import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core'
+import { Component, ElementRef, LOCALE_ID, NgZone, OnDestroy, OnInit, ViewChild, Inject } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { RedirectService } from '@app/core/routing/redirect.service'
import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
import { VideoDownloadComponent } from './modal/video-download.component'
import { VideoReportComponent } from './modal/video-report.component'
import { VideoShareComponent } from './modal/video-share.component'
-import { getVideojsOptions } from '../../../assets/player/peertube-player'
+import { getVideojsOptions, loadLocale, addContextMenu } from '../../../assets/player/peertube-player'
import { ServerService } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
+import { environment } from '../../../environments/environment'
@Component({
selector: 'my-video-watch',
likesBarTooltipText = ''
hasAlreadyAcceptedPrivacyConcern = false
+ private videojsLocaleLoaded = false
private otherVideos: Video[] = []
private paramsSub: Subscription
private markdownService: MarkdownService,
private zone: NgZone,
private redirectService: RedirectService,
- private i18n: I18n
+ private i18n: I18n,
+ @Inject(LOCALE_ID) private localeId: string
) {}
get user () {
inactivityTimeout: 2500,
videoFiles: this.video.files,
playerElement: this.playerElement,
- videoEmbedUrl: this.video.embedUrl,
videoViewUrl: this.videoService.getVideoViewUrl(this.video.uuid),
videoDuration: this.video.duration,
enableHotkeys: true,
startTime
})
+ if (this.videojsLocaleLoaded === false) {
+ await loadLocale(environment.apiUrl, videojs, environment.production === true ? this.localeId : 'fr')
+ this.videojsLocaleLoaded = true
+ }
+
const self = this
- this.zone.runOutsideAngular(() => {
+ this.zone.runOutsideAngular(async () => {
videojs(this.playerElement, videojsOptions, function () {
self.player = this
this.on('customError', (event, data) => self.handleError(data.err))
+
+ addContextMenu(self.player, self.video.embedUrl)
})
})
const el = videojsUntyped.dom.createEl('a', {
href: buildVideoLink(),
innerHTML: 'PeerTube',
- title: 'Go to the video page',
+ title: this.player_.localize('Go to the video page'),
className: 'vjs-peertube-link',
target: '_blank'
})
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'
// Change 'Playback Rate' to 'Speed' (smaller for our settings menu)
videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed'
autoplay: boolean,
playerElement: HTMLVideoElement,
videoViewUrl: string,
- videoEmbedUrl: string,
videoDuration: number,
videoFiles: VideoFile[],
enableHotkeys: boolean,
videoViewUrl: options.videoViewUrl,
videoDuration: options.videoDuration,
startTime: options.startTime
- },
- contextmenuUI: {
- content: [
- {
- label: 'Copy the video URL',
- listener: function () {
- copyToClipboard(buildVideoLink())
- }
- },
- {
- label: 'Copy the video URL at the current time',
- listener: function () {
- const player = this
- copyToClipboard(buildVideoLink(player.currentTime()))
- }
- },
- {
- label: 'Copy embed code',
- listener: () => {
- copyToClipboard(buildVideoEmbed(options.videoEmbedUrl))
- }
- }
- ]
}
},
controlBar: {
return children
}
-export { getVideojsOptions }
+function addContextMenu (player: any, videoEmbedUrl: string) {
+ console.log(videoEmbedUrl)
+
+ player.contextmenuUI({
+ content: [
+ {
+ label: player.localize('Copy the video URL'),
+ listener: function () {
+ copyToClipboard(buildVideoLink())
+ }
+ },
+ {
+ label: player.localize('Copy the video URL at the current time'),
+ listener: function () {
+ const player = this
+ copyToClipboard(buildVideoLink(player.currentTime()))
+ }
+ },
+ {
+ label: player.localize('Copy embed code'),
+ listener: () => {
+ copyToClipboard(buildVideoEmbed(videoEmbedUrl))
+ }
+ }
+ ]
+ })
+}
+
+function loadLocale (serverUrl: string, videojs: any, locale: string) {
+ if (!is18nLocale(locale) || isDefaultLocale(locale)) return undefined
+
+ return fetch(serverUrl + '/client/locales/' + locale + '/player.json')
+ .then(res => res.json())
+ .then(json => videojs.addLanguage(locale, json))
+}
+
+export {
+ loadLocale,
+ getVideojsOptions,
+ addContextMenu
+}
import { renderVideo } from './video-renderer'
import './settings-menu-button'
import { PeertubePluginOptions, VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
-import {
- getAverageBandwidth,
- getStoredMute,
- getStoredVolume,
- isMobile,
- saveAverageBandwidth,
- saveMuteInStore,
- saveVolumeInStore
-} from './utils'
+import { getAverageBandwidth, getStoredMute, getStoredVolume, saveAverageBandwidth, saveMuteInStore, saveVolumeInStore } from './utils'
import minBy from 'lodash-es/minBy'
import maxBy from 'lodash-es/maxBy'
import * as CacheChunkStore from 'cache-chunk-store'
label: HTMLElement
constructor (player: videojs.Player, options) {
- options.label = 'Quality'
super(player, options)
-
- this.controlText_ = 'Quality'
this.player = player
player.peertube().on('videoFileUpdate', () => this.updateLabel())
this.player_,
{
id: -1,
- label: 'Auto',
+ label: this.player_.localize('Auto'),
src: null
}
))
return this.player_.peertube().getCurrentResolutionLabel()
}
}
+ResolutionMenuButton.prototype.controlText_ = 'Quality'
+
MenuButton.registerComponent('ResolutionMenuButton', ResolutionMenuButton)
}
-SettingsButton.prototype.controlText_ = 'Settings Button'
+SettingsButton.prototype.controlText_ = 'Settings'
Component.registerComponent('SettingsButton', SettingsButton)
Component.registerComponent('SettingsDialog', SettingsDialog)
const button = this.subMenu.menu.addChild('MenuItem', {}, 0)
button.name_ = 'BackButton'
button.addClass('vjs-back-button')
- button.el_.innerHTML = this.subMenu.controlText_
+ button.el_.innerHTML = this.player_.localize(this.subMenu.controlText_)
}
/**
saveUpdateLabel.call(this.subMenu)
}
- this.settingsSubMenuTitleEl_.innerHTML = this.subMenu.controlText_
+ this.settingsSubMenuTitleEl_.innerHTML = this.player_.localize(this.subMenu.controlText_)
this.settingsSubMenuEl_.appendChild(this.subMenu.menu.el_)
this.panelChildEl.appendChild(this.settingsSubMenuEl_)
this.update()
+import { is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n'
+
function toTitleCase (str: string) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
className: 'peers-number',
textContent: 'HTTP'
})
- const subDivFallbackText = videojsUntyped.dom.createEl('span', {
- className: 'peers-text',
- textContent: ' fallback'
- })
subDivHttp.appendChild(subDivHttpText)
- subDivHttp.appendChild(subDivFallbackText)
div.appendChild(subDivHttp)
this.player_.peertube().on('torrentInfo', (event, data) => {
uploadSpeedUnit.textContent = ' ' + uploadSpeed[ 1 ]
peersNumber.textContent = numPeers
- peersText.textContent = ' peers'
+ peersText.textContent = ' ' + this.player_.localize('peers')
subDivHttp.className = 'vjs-peertube-hidden'
subDivWebtorrent.className = 'vjs-peertube-displayed'
--- /dev/null
+<xliff xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 http://docs.oasis-open.org/xliff/v1.2/os/xliff-core-1.2-strict.xsd" xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
+ <file original="namespace1" datatype="plaintext" source-language="undefined" target-language="undefined">
+ <body>
+ <trans-unit id="Audio Player">
+ <source>Audio Player</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Video Player">
+ <source>Video Player</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Play">
+ <source>Play</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Pause">
+ <source>Pause</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Replay">
+ <source>Replay</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Current Time">
+ <source>Current Time</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Duration">
+ <source>Duration</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Remaining Time">
+ <source>Remaining Time</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Stream Type">
+ <source>Stream Type</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="LIVE">
+ <source>LIVE</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Loaded">
+ <source>Loaded</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Progress">
+ <source>Progress</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Progress Bar">
+ <source>Progress Bar</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="progress bar timing: currentTime={1} duration={2}">
+ <source>{1} of {2}</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Fullscreen">
+ <source>Fullscreen</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Non-Fullscreen">
+ <source>Non-Fullscreen</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Mute">
+ <source>Mute</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Unmute">
+ <source>Unmute</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Playback Rate">
+ <source>Playback Rate</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Subtitles">
+ <source>Subtitles</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="subtitles off">
+ <source>subtitles off</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Captions">
+ <source>Captions</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="captions off">
+ <source>captions off</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Chapters">
+ <source>Chapters</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Descriptions">
+ <source>Descriptions</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="descriptions off">
+ <source>descriptions off</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Audio Track">
+ <source>Audio Track</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Volume Level">
+ <source>Volume Level</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="You aborted the media playback">
+ <source>You aborted the media playback</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="A network error caused the media download to fail part-way.">
+ <source>A network error caused the media download to fail part-way.</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="The media could not be loaded, either because the server or network failed or because the format is not supported.">
+ <source>The media could not be loaded, either because the server or network failed or because the format is not supported.</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="The media playback was aborted due to a corruption problem or because the media used features your browser did not support.">
+ <source>The media playback was aborted due to a corruption problem or because the media used features your browser did not support.</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="No compatible source was found for this media.">
+ <source>No compatible source was found for this media.</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="The media is encrypted and we do not have the keys to decrypt it.">
+ <source>The media is encrypted and we do not have the keys to decrypt it.</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Play Video">
+ <source>Play Video</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Close">
+ <source>Close</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Close Modal Dialog">
+ <source>Close Modal Dialog</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Modal Window">
+ <source>Modal Window</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="This is a modal window">
+ <source>This is a modal window</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="This modal can be closed by pressing the Escape key or activating the close button.">
+ <source>This modal can be closed by pressing the Escape key or activating the close button.</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id=", opens captions settings dialog">
+ <source>, opens captions settings dialog</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id=", opens subtitles settings dialog">
+ <source>, opens subtitles settings dialog</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id=", opens descriptions settings dialog">
+ <source>, opens descriptions settings dialog</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id=", selected">
+ <source>, selected</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="captions settings">
+ <source>captions settings</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="subtitles settings">
+ <source>subititles settings</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="descriptions settings">
+ <source>descriptions settings</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Text">
+ <source>Text</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="White">
+ <source>White</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Black">
+ <source>Black</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Red">
+ <source>Red</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Green">
+ <source>Green</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Blue">
+ <source>Blue</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Yellow">
+ <source>Yellow</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Magenta">
+ <source>Magenta</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Cyan">
+ <source>Cyan</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Background">
+ <source>Background</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Window">
+ <source>Window</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Transparent">
+ <source>Transparent</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Semi-Transparent">
+ <source>Semi-Transparent</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Opaque">
+ <source>Opaque</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Font Size">
+ <source>Font Size</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Text Edge Style">
+ <source>Text Edge Style</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="None">
+ <source>None</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Raised">
+ <source>Raised</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Depressed">
+ <source>Depressed</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Uniform">
+ <source>Uniform</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Dropshadow">
+ <source>Dropshadow</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Font Family">
+ <source>Font Family</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Proportional Sans-Serif">
+ <source>Proportional Sans-Serif</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Monospace Sans-Serif">
+ <source>Monospace Sans-Serif</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Proportional Serif">
+ <source>Proportional Serif</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Monospace Serif">
+ <source>Monospace Serif</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Casual">
+ <source>Casual</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Script">
+ <source>Script</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Small Caps">
+ <source>Small Caps</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Reset">
+ <source>Reset</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="restore all settings to the default values">
+ <source>restore all settings to the default values</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Done">
+ <source>Done</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Caption Settings Dialog">
+ <source>Caption Settings Dialog</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Beginning of dialog window. Escape will cancel and close the window.">
+ <source>Beginning of dialog window. Escape will cancel and close the window.</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="End of dialog window.">
+ <source>End of dialog window.</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="{1} is loading.">
+ <source>{1} is loading.</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Quality">
+ <source>Quality</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Auto">
+ <source>Auto</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Speed">
+ <source>Speed</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="peers">
+ <source>peers</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Go to the video page">
+ <source>Go to the video page</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Settings">
+ <source>Settings</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Uses P2P, others may know you are watching this video.">
+ <source>Uses P2P, others may know you are watching this video.</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Copy the video URL">
+ <source>Copy the video URL</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Copy the video URL at the current time">
+ <source>Copy the video URL at the current time</source>
+ <target>undefined</target>
+ </trans-unit>
+ <trans-unit id="Copy embed code">
+ <source>Copy embed code</source>
+ <target>undefined</target>
+ </trans-unit>
+ </body>
+ </file>
+</xliff>
\ No newline at end of file
--- /dev/null
+{
+ "Audio Player": "Audio Player",
+ "Video Player": "Video Player",
+ "Play": "Play",
+ "Pause": "Pause",
+ "Replay": "Replay",
+ "Current Time": "Current Time",
+ "Duration": "Duration",
+ "Remaining Time": "Remaining Time",
+ "Stream Type": "Stream Type",
+ "LIVE": "LIVE",
+ "Loaded": "Loaded",
+ "Progress": "Progress",
+ "Progress Bar": "Progress Bar",
+ "progress bar timing: currentTime={1} duration={2}": "{1} of {2}",
+ "Fullscreen": "Fullscreen",
+ "Non-Fullscreen": "Non-Fullscreen",
+ "Mute": "Mute",
+ "Unmute": "Unmute",
+ "Playback Rate": "Playback Rate",
+ "Subtitles": "Subtitles",
+ "subtitles off": "subtitles off",
+ "Captions": "Captions",
+ "captions off": "captions off",
+ "Chapters": "Chapters",
+ "Descriptions": "Descriptions",
+ "descriptions off": "descriptions off",
+ "Audio Track": "Audio Track",
+ "Volume Level": "Volume Level",
+ "You aborted the media playback": "You aborted the media playback",
+ "A network error caused the media download to fail part-way.": "A network error caused the media download to fail part-way.",
+ "The media could not be loaded, either because the server or network failed or because the format is not supported.": "The media could not be loaded, either because the server or network failed or because the format is not supported.",
+ "The media playback was aborted due to a corruption problem or because the media used features your browser did not support.": "The media playback was aborted due to a corruption problem or because the media used features your browser did not support.",
+ "No compatible source was found for this media.": "No compatible source was found for this media.",
+ "The media is encrypted and we do not have the keys to decrypt it.": "The media is encrypted and we do not have the keys to decrypt it.",
+ "Play Video": "Play Video",
+ "Close": "Close",
+ "Close Modal Dialog": "Close Modal Dialog",
+ "Modal Window": "Modal Window",
+ "This is a modal window": "This is a modal window",
+ "This modal can be closed by pressing the Escape key or activating the close button.": "This modal can be closed by pressing the Escape key or activating the close button.",
+ ", opens captions settings dialog": ", opens captions settings dialog",
+ ", opens subtitles settings dialog": ", opens subtitles settings dialog",
+ ", opens descriptions settings dialog": ", opens descriptions settings dialog",
+ ", selected": ", selected",
+ "captions settings": "captions settings",
+ "subtitles settings": "subititles settings",
+ "descriptions settings": "descriptions settings",
+ "Text": "Text",
+ "White": "White",
+ "Black": "Black",
+ "Red": "Red",
+ "Green": "Green",
+ "Blue": "Blue",
+ "Yellow": "Yellow",
+ "Magenta": "Magenta",
+ "Cyan": "Cyan",
+ "Background": "Background",
+ "Window": "Window",
+ "Transparent": "Transparent",
+ "Semi-Transparent": "Semi-Transparent",
+ "Opaque": "Opaque",
+ "Font Size": "Font Size",
+ "Text Edge Style": "Text Edge Style",
+ "None": "None",
+ "Raised": "Raised",
+ "Depressed": "Depressed",
+ "Uniform": "Uniform",
+ "Dropshadow": "Dropshadow",
+ "Font Family": "Font Family",
+ "Proportional Sans-Serif": "Proportional Sans-Serif",
+ "Monospace Sans-Serif": "Monospace Sans-Serif",
+ "Proportional Serif": "Proportional Serif",
+ "Monospace Serif": "Monospace Serif",
+ "Casual": "Casual",
+ "Script": "Script",
+ "Small Caps": "Small Caps",
+ "Reset": "Reset",
+ "restore all settings to the default values": "restore all settings to the default values",
+ "Done": "Done",
+ "Caption Settings Dialog": "Caption Settings Dialog",
+ "Beginning of dialog window. Escape will cancel and close the window.": "Beginning of dialog window. Escape will cancel and close the window.",
+ "End of dialog window.": "End of dialog window.",
+ "{1} is loading.": "{1} is loading."
+}
--- /dev/null
+{"Audio Player":"Lecteur audio","Video Player":"Lecteur vidéo","Play":"Lecture","Pause":"Pause","Replay":"Revoir","Current Time":"Temps actuel","Duration":"Durée","Remaining Time":"Temps restant","Stream Type":"Type de flux","LIVE":"EN DIRECT","Loaded":"Chargé","Progress":"Progression","Progress Bar":"Barre de progression","progress bar timing: currentTime={1} duration={2}":"{1} de {2}","Fullscreen":"Plein écran","Non-Fullscreen":"Fenêtré","Mute":"Sourdine","Unmute":"Son activé","Playback Rate":"Vitesse de lecture","Subtitles":"Sous-titres","subtitles off":"Sous-titres désactivés","Captions":"Sous-titres transcrits","captions off":"Sous-titres transcrits désactivés","Chapters":"Chapitres","Descriptions":"Descriptions","descriptions off":"descriptions désactivées","Audio Track":"Piste audio","Volume Level":"Niveau de volume","You aborted the media playback":"Vous avez interrompu la lecture de la vidéo.","A network error caused the media download to fail part-way.":"Une erreur de réseau a interrompu le téléchargement de la vidéo.","The media could not be loaded, either because the server or network failed or because the format is not supported.":"Cette vidéo n'a pas pu être chargée, soit parce que le serveur ou le réseau a échoué ou parce que le format n'est pas reconnu.","The media playback was aborted due to a corruption problem or because the media used features your browser did not support.":"La lecture de la vidéo a été interrompue à cause d'un problème de corruption ou parce que la vidéo utilise des fonctionnalités non prises en charge par votre navigateur.","No compatible source was found for this media.":"Aucune source compatible n'a été trouvée pour cette vidéo.","The media is encrypted and we do not have the keys to decrypt it.":"Le média est chiffré et nous n'avons pas les clés pour le déchiffrer.","Play Video":"Lire la vidéo","Close":"Fermer","Close Modal Dialog":"Fermer la boîte de dialogue modale","Modal Window":"Fenêtre modale","This is a modal window":"Ceci est une fenêtre modale","This modal can be closed by pressing the Escape key or activating the close button.":"Ce modal peut être fermé en appuyant sur la touche Échap ou activer le bouton de fermeture.",", opens captions settings dialog":", ouvrir les paramètres des sous-titres transcrits",", opens subtitles settings dialog":", ouvrir les paramètres des sous-titres",", opens descriptions settings dialog":", ouvrir les paramètres des descriptions",", selected":", sélectionné","captions settings":"Paramètres des sous-titres transcrits","subtitles settings":"Paramètres des sous-titres","descriptions settings":"Paramètres des descriptions","Text":"Texte","White":"Blanc","Black":"Noir","Red":"Rouge","Green":"Vert","Blue":"Bleu","Yellow":"Jaune","Magenta":"Magenta","Cyan":"Cyan","Background":"Arrière-plan","Window":"Fenêtre","Transparent":"Transparent","Semi-Transparent":"Semi-transparent","Opaque":"Opaque","Font Size":"Taille des caractères","Text Edge Style":"Style des contours du texte","None":"Aucun","Raised":"Élevé","Depressed":"Enfoncé","Uniform":"Uniforme","Dropshadow":"Ombre portée","Font Family":"Familles de polices","Proportional Sans-Serif":"Polices à chasse variable sans empattement (Proportional Sans-Serif)","Monospace Sans-Serif":"Polices à chasse fixe sans empattement (Monospace Sans-Serif)","Proportional Serif":"Polices à chasse variable avec empattement (Proportional Serif)","Monospace Serif":"Polices à chasse fixe avec empattement (Monospace Serif)","Casual":"Manuscrite","Script":"Scripte","Small Caps":"Petites capitales","Reset":"Réinitialiser","restore all settings to the default values":"Restaurer tous les paramètres aux valeurs par défaut","Done":"Terminé","Caption Settings Dialog":"Boîte de dialogue des paramètres des sous-titres transcrits","Beginning of dialog window. Escape will cancel and close the window.":"Début de la fenêtre de dialogue. La touche d'échappement annulera et fermera la fenêtre.","End of dialog window.":"Fin de la fenêtre de dialogue.","{1} is loading.":"{1} est en train de charger","Quality":"Qualité","Auto":"Auto","Speed":"Vitesse","peers":"pairs","Go to the video page":"Aller sur la page de la vidéo","Settings":"Paramètres","Uses P2P, others may know you are watching this video.":"Utilise le P2P, d'autres personnes pourraient savoir que vous regardez cette vidéo.","Copy the video URL":"Copier le lien de la vidéo","Copy the video URL at the current time":"Copier le lien de la vidéo à partir de cette séquence","Copy embed code":"Copier le code d'intégration"}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--XLIFF document generated by Zanata. Visit http://zanata.org for more infomation.-->
+<xliff xmlns="urn:oasis:names:tc:xliff:document:1.1" xmlns:xyz="urn:appInfo:Items" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.1 http://www.oasis-open.org/committees/xliff/documents/xliff-core-1.1.xsd" version="1.1">
+ <file source-language="en-US" datatype="plaintext" original="" target-language="fr">
+ <body>
+ <trans-unit id="Audio Player">
+ <source>Audio Player</source>
+ <target>Lecteur audio</target>
+ </trans-unit>
+ <trans-unit id="Video Player">
+ <source>Video Player</source>
+ <target>Lecteur vidéo</target>
+ </trans-unit>
+ <trans-unit id="Play">
+ <source>Play</source>
+ <target>Lecture</target>
+ </trans-unit>
+ <trans-unit id="Pause">
+ <source>Pause</source>
+ <target>Pause</target>
+ </trans-unit>
+ <trans-unit id="Replay">
+ <source>Replay</source>
+ <target>Revoir</target>
+ </trans-unit>
+ <trans-unit id="Current Time">
+ <source>Current Time</source>
+ <target>Temps actuel</target>
+ </trans-unit>
+ <trans-unit id="Duration">
+ <source>Duration</source>
+ <target>Durée</target>
+ </trans-unit>
+ <trans-unit id="Remaining Time">
+ <source>Remaining Time</source>
+ <target>Temps restant</target>
+ </trans-unit>
+ <trans-unit id="Stream Type">
+ <source>Stream Type</source>
+ <target>Type de flux</target>
+ </trans-unit>
+ <trans-unit id="LIVE">
+ <source>LIVE</source>
+ <target>EN DIRECT</target>
+ </trans-unit>
+ <trans-unit id="Loaded">
+ <source>Loaded</source>
+ <target>Chargé</target>
+ </trans-unit>
+ <trans-unit id="Progress">
+ <source>Progress</source>
+ <target>Progression</target>
+ </trans-unit>
+ <trans-unit id="Progress Bar">
+ <source>Progress Bar</source>
+ <target>Barre de progression</target>
+ </trans-unit>
+ <trans-unit id="progress bar timing: currentTime={1} duration={2}">
+ <source>{1} of {2}</source>
+ <target>{1} de {2}</target>
+ </trans-unit>
+ <trans-unit id="Fullscreen">
+ <source>Fullscreen</source>
+ <target>Plein écran</target>
+ </trans-unit>
+ <trans-unit id="Non-Fullscreen">
+ <source>Non-Fullscreen</source>
+ <target>Fenêtré</target>
+ </trans-unit>
+ <trans-unit id="Mute">
+ <source>Mute</source>
+ <target>Sourdine</target>
+ </trans-unit>
+ <trans-unit id="Unmute">
+ <source>Unmute</source>
+ <target>Son activé</target>
+ </trans-unit>
+ <trans-unit id="Playback Rate">
+ <source>Playback Rate</source>
+ <target>Vitesse de lecture</target>
+ </trans-unit>
+ <trans-unit id="Subtitles">
+ <source>Subtitles</source>
+ <target>Sous-titres</target>
+ </trans-unit>
+ <trans-unit id="subtitles off">
+ <source>subtitles off</source>
+ <target>Sous-titres désactivés</target>
+ </trans-unit>
+ <trans-unit id="Captions">
+ <source>Captions</source>
+ <target>Sous-titres transcrits</target>
+ </trans-unit>
+ <trans-unit id="captions off">
+ <source>captions off</source>
+ <target>Sous-titres transcrits désactivés</target>
+ </trans-unit>
+ <trans-unit id="Chapters">
+ <source>Chapters</source>
+ <target>Chapitres</target>
+ </trans-unit>
+ <trans-unit id="Descriptions">
+ <source>Descriptions</source>
+ <target>Descriptions</target>
+ </trans-unit>
+ <trans-unit id="descriptions off">
+ <source>descriptions off</source>
+ <target>descriptions désactivées</target>
+ </trans-unit>
+ <trans-unit id="Audio Track">
+ <source>Audio Track</source>
+ <target>Piste audio</target>
+ </trans-unit>
+ <trans-unit id="Volume Level">
+ <source>Volume Level</source>
+ <target>Niveau de volume</target>
+ </trans-unit>
+ <trans-unit id="You aborted the media playback">
+ <source>You aborted the media playback</source>
+ <target>Vous avez interrompu la lecture de la vidéo.</target>
+ </trans-unit>
+ <trans-unit id="A network error caused the media download to fail part-way.">
+ <source>A network error caused the media download to fail part-way.</source>
+ <target>Une erreur de réseau a interrompu le téléchargement de la vidéo.</target>
+ </trans-unit>
+ <trans-unit id="The media could not be loaded, either because the server or network failed or because the format is not supported.">
+ <source>The media could not be loaded, either because the server or network failed or because the format is not supported.</source>
+ <target>Cette vidéo n'a pas pu être chargée, soit parce que le serveur ou le réseau a échoué ou parce que le format n'est pas reconnu.</target>
+ </trans-unit>
+ <trans-unit id="The media playback was aborted due to a corruption problem or because the media used features your browser did not support.">
+ <source>The media playback was aborted due to a corruption problem or because the media used features your browser did not support.</source>
+ <target>La lecture de la vidéo a été interrompue à cause d'un problème de corruption ou parce que la vidéo utilise des fonctionnalités non prises en charge par votre navigateur.</target>
+ </trans-unit>
+ <trans-unit id="No compatible source was found for this media.">
+ <source>No compatible source was found for this media.</source>
+ <target>Aucune source compatible n'a été trouvée pour cette vidéo.</target>
+ </trans-unit>
+ <trans-unit id="The media is encrypted and we do not have the keys to decrypt it.">
+ <source>The media is encrypted and we do not have the keys to decrypt it.</source>
+ <target>Le média est chiffré et nous n'avons pas les clés pour le déchiffrer.</target>
+ </trans-unit>
+ <trans-unit id="Play Video">
+ <source>Play Video</source>
+ <target>Lire la vidéo</target>
+ </trans-unit>
+ <trans-unit id="Close">
+ <source>Close</source>
+ <target>Fermer</target>
+ </trans-unit>
+ <trans-unit id="Close Modal Dialog">
+ <source>Close Modal Dialog</source>
+ <target>Fermer la boîte de dialogue modale</target>
+ </trans-unit>
+ <trans-unit id="Modal Window">
+ <source>Modal Window</source>
+ <target>Fenêtre modale</target>
+ </trans-unit>
+ <trans-unit id="This is a modal window">
+ <source>This is a modal window</source>
+ <target>Ceci est une fenêtre modale</target>
+ </trans-unit>
+ <trans-unit id="This modal can be closed by pressing the Escape key or activating the close button.">
+ <source>This modal can be closed by pressing the Escape key or activating the close button.</source>
+ <target>Ce modal peut être fermé en appuyant sur la touche Échap ou activer le bouton de fermeture.</target>
+ </trans-unit>
+ <trans-unit id=", opens captions settings dialog">
+ <source>, opens captions settings dialog</source>
+ <target>, ouvrir les paramètres des sous-titres transcrits</target>
+ </trans-unit>
+ <trans-unit id=", opens subtitles settings dialog">
+ <source>, opens subtitles settings dialog</source>
+ <target>, ouvrir les paramètres des sous-titres</target>
+ </trans-unit>
+ <trans-unit id=", opens descriptions settings dialog">
+ <source>, opens descriptions settings dialog</source>
+ <target>, ouvrir les paramètres des descriptions</target>
+ </trans-unit>
+ <trans-unit id=", selected">
+ <source>, selected</source>
+ <target>, sélectionné</target>
+ </trans-unit>
+ <trans-unit id="captions settings">
+ <source>captions settings</source>
+ <target>Paramètres des sous-titres transcrits</target>
+ </trans-unit>
+ <trans-unit id="subtitles settings">
+ <source>subititles settings</source>
+ <target>Paramètres des sous-titres</target>
+ </trans-unit>
+ <trans-unit id="descriptions settings">
+ <source>descriptions settings</source>
+ <target>Paramètres des descriptions</target>
+ </trans-unit>
+ <trans-unit id="Text">
+ <source>Text</source>
+ <target>Texte</target>
+ </trans-unit>
+ <trans-unit id="White">
+ <source>White</source>
+ <target>Blanc</target>
+ </trans-unit>
+ <trans-unit id="Black">
+ <source>Black</source>
+ <target>Noir</target>
+ </trans-unit>
+ <trans-unit id="Red">
+ <source>Red</source>
+ <target>Rouge</target>
+ </trans-unit>
+ <trans-unit id="Green">
+ <source>Green</source>
+ <target>Vert</target>
+ </trans-unit>
+ <trans-unit id="Blue">
+ <source>Blue</source>
+ <target>Bleu</target>
+ </trans-unit>
+ <trans-unit id="Yellow">
+ <source>Yellow</source>
+ <target>Jaune</target>
+ </trans-unit>
+ <trans-unit id="Magenta">
+ <source>Magenta</source>
+ <target>Magenta</target>
+ </trans-unit>
+ <trans-unit id="Cyan">
+ <source>Cyan</source>
+ <target>Cyan</target>
+ </trans-unit>
+ <trans-unit id="Background">
+ <source>Background</source>
+ <target>Arrière-plan</target>
+ </trans-unit>
+ <trans-unit id="Window">
+ <source>Window</source>
+ <target>Fenêtre</target>
+ </trans-unit>
+ <trans-unit id="Transparent">
+ <source>Transparent</source>
+ <target>Transparent</target>
+ </trans-unit>
+ <trans-unit id="Semi-Transparent">
+ <source>Semi-Transparent</source>
+ <target>Semi-transparent</target>
+ </trans-unit>
+ <trans-unit id="Opaque">
+ <source>Opaque</source>
+ <target>Opaque</target>
+ </trans-unit>
+ <trans-unit id="Font Size">
+ <source>Font Size</source>
+ <target>Taille des caractères</target>
+ </trans-unit>
+ <trans-unit id="Text Edge Style">
+ <source>Text Edge Style</source>
+ <target>Style des contours du texte</target>
+ </trans-unit>
+ <trans-unit id="None">
+ <source>None</source>
+ <target>Aucun</target>
+ </trans-unit>
+ <trans-unit id="Raised">
+ <source>Raised</source>
+ <target>Élevé</target>
+ </trans-unit>
+ <trans-unit id="Depressed">
+ <source>Depressed</source>
+ <target>Enfoncé</target>
+ </trans-unit>
+ <trans-unit id="Uniform">
+ <source>Uniform</source>
+ <target>Uniforme</target>
+ </trans-unit>
+ <trans-unit id="Dropshadow">
+ <source>Dropshadow</source>
+ <target>Ombre portée</target>
+ </trans-unit>
+ <trans-unit id="Font Family">
+ <source>Font Family</source>
+ <target>Familles de polices</target>
+ </trans-unit>
+ <trans-unit id="Proportional Sans-Serif">
+ <source>Proportional Sans-Serif</source>
+ <target>Polices à chasse variable sans empattement (Proportional Sans-Serif)</target>
+ </trans-unit>
+ <trans-unit id="Monospace Sans-Serif">
+ <source>Monospace Sans-Serif</source>
+ <target>Polices à chasse fixe sans empattement (Monospace Sans-Serif)</target>
+ </trans-unit>
+ <trans-unit id="Proportional Serif">
+ <source>Proportional Serif</source>
+ <target>Polices à chasse variable avec empattement (Proportional Serif)</target>
+ </trans-unit>
+ <trans-unit id="Monospace Serif">
+ <source>Monospace Serif</source>
+ <target>Polices à chasse fixe avec empattement (Monospace Serif)</target>
+ </trans-unit>
+ <trans-unit id="Casual">
+ <source>Casual</source>
+ <target>Manuscrite</target>
+ </trans-unit>
+ <trans-unit id="Script">
+ <source>Script</source>
+ <target>Scripte</target>
+ </trans-unit>
+ <trans-unit id="Small Caps">
+ <source>Small Caps</source>
+ <target>Petites capitales</target>
+ </trans-unit>
+ <trans-unit id="Reset">
+ <source>Reset</source>
+ <target>Réinitialiser</target>
+ </trans-unit>
+ <trans-unit id="restore all settings to the default values">
+ <source>restore all settings to the default values</source>
+ <target>Restaurer tous les paramètres aux valeurs par défaut</target>
+ </trans-unit>
+ <trans-unit id="Done">
+ <source>Done</source>
+ <target>Terminé</target>
+ </trans-unit>
+ <trans-unit id="Caption Settings Dialog">
+ <source>Caption Settings Dialog</source>
+ <target>Boîte de dialogue des paramètres des sous-titres transcrits</target>
+ </trans-unit>
+ <trans-unit id="Beginning of dialog window. Escape will cancel and close the window.">
+ <source>Beginning of dialog window. Escape will cancel and close the window.</source>
+ <target>Début de la fenêtre de dialogue. La touche d'échappement annulera et fermera la fenêtre.</target>
+ </trans-unit>
+ <trans-unit id="End of dialog window.">
+ <source>End of dialog window.</source>
+ <target>Fin de la fenêtre de dialogue.</target>
+ </trans-unit>
+ <trans-unit id="{1} is loading.">
+ <source>{1} is loading.</source>
+ <target>{1} est en train de charger</target>
+ </trans-unit>
+ <trans-unit id="Quality">
+ <source>Quality</source>
+ <target>Qualité</target>
+ </trans-unit>
+ <trans-unit id="Auto">
+ <source>Auto</source>
+ <target>Auto</target>
+ </trans-unit>
+ <trans-unit id="Speed">
+ <source>Speed</source>
+ <target>Vitesse</target>
+ </trans-unit>
+ <trans-unit id="peers">
+ <source>peers</source>
+ <target>pairs</target>
+ </trans-unit>
+ <trans-unit id="Go to the video page">
+ <source>Go to the video page</source>
+ <target>Aller sur la page de la vidéo</target>
+ </trans-unit>
+ <trans-unit id="Settings">
+ <source>Settings</source>
+ <target>Paramètres</target>
+ </trans-unit>
+ <trans-unit id="Uses P2P, others may know you are watching this video.">
+ <source>Uses P2P, others may know you are watching this video.</source>
+ <target>Utilise le P2P, d'autres personnes pourraient savoir que vous regardez cette vidéo.</target>
+ </trans-unit>
+ <trans-unit id="Copy the video URL">
+ <source>Copy the video URL</source>
+ <target>Copier le lien de la vidéo</target>
+ </trans-unit>
+ <trans-unit id="Copy the video URL at the current time">
+ <source>Copy the video URL at the current time</source>
+ <target>Copier le lien de la vidéo à partir de cette séquence</target>
+ </trans-unit>
+ <trans-unit id="Copy embed code">
+ <source>Copy embed code</source>
+ <target>Copier le code d'intégration</target>
+ </trans-unit>
+ </body>
+ </file></xliff>
\ No newline at end of file
import 'core-js/es6/map'
import 'core-js/es6/weak-map'
import 'core-js/es6/set'
-
// For google bot that uses Chrome 41 and does not understand fetch
import 'whatwg-fetch'
import * as videojs from 'video.js'
import { VideoDetails } from '../../../../shared'
-import { getVideojsOptions } from '../../assets/player/peertube-player'
+import { addContextMenu, getVideojsOptions, loadLocale } from '../../assets/player/peertube-player'
+import { environment } from '../../environments/environment'
function getVideoUrl (id: string) {
return window.location.origin + '/api/v1/videos/' + id
const urlParts = window.location.href.split('/')
const videoId = urlParts[urlParts.length - 1]
-loadVideoInfo(videoId)
+loadLocale(environment.apiUrl, videojs, navigator.language)
+ .then(() => loadVideoInfo(videoId))
.then(async response => {
const videoContainerId = 'video-container'
const videoElement = document.getElementById(videoContainerId) as HTMLVideoElement
const videojsOptions = getVideojsOptions({
autoplay,
inactivityTimeout: 1500,
- videoEmbedUrl: window.location.origin + videoInfo.embedPath,
videoViewUrl: getVideoUrl(videoId) + '/views',
playerElement: videoElement,
videoFiles: videoInfo.files,
player.dock({
title: videoInfo.name,
- description: 'Uses P2P, others may know you are watching this video.'
+ description: player.localize('Uses P2P, others may know you are watching this video.')
})
+
+ addContextMenu(player, window.location.origin + videoInfo.embedPath)
})
})
.catch(err => console.error(err))
"danger:clean:prod": "scripty",
"danger:clean:modules": "scripty",
"i18n:generate": "scripty",
+ "i18n:xliff2json": "node ./dist/scripts/i18n/xliff2json.js",
+ "i18n:create-custom-files": "node ./dist/scripts/i18n/create-custom-files.js",
"reset-password": "node ./dist/scripts/reset-password.js",
"play": "scripty",
"dev": "scripty",
"tslint-config-standard": "^7.0.0",
"typescript": "^2.5.2",
"webtorrent": "^0.100.0",
+ "xliff": "^3.0.1",
"youtube-dl": "^1.12.2"
},
"scripty": {
--- /dev/null
+import * as jsToXliff12 from 'xliff/jsToXliff12'
+import { writeFile } from 'fs'
+import { join } from 'path'
+
+// First, the player
+const playerSource = join(__dirname, '../../../client/src/locale/source/videojs_en_US.json')
+const playerTarget = join(__dirname, '../../../client/src/locale/source/player_en_US.xml')
+
+const videojs = require(playerSource)
+const playerKeys = {
+ 'Quality': 'Quality',
+ 'Auto': 'Auto',
+ 'Speed': 'Speed',
+ 'peers': 'peers',
+ 'Go to the video page': 'Go to the video page',
+ 'Settings': 'Settings',
+ 'Uses P2P, others may know you are watching this video.': 'Uses P2P, others may know you are watching this video.',
+ 'Copy the video URL': 'Copy the video URL',
+ 'Copy the video URL at the current time': 'Copy the video URL at the current time',
+ 'Copy embed code': 'Copy embed code'
+}
+
+const obj = {
+ resources: {
+ namespace1: {}
+ }
+}
+
+for (const sourceObject of [ videojs, playerKeys ]) {
+ Object.keys(sourceObject).forEach(k => obj.resources.namespace1[ k ] = { source: sourceObject[ k ] })
+}
+
+jsToXliff12(obj, (err, res) => {
+ if (err) {
+ console.error(err)
+ process.exit(-1)
+ }
+
+ writeFile(playerTarget, res, err => {
+ if (err) {
+ console.error(err)
+ process.exit(-1)
+ }
+
+ process.exit(0)
+ })
+})
+
+// Then, the server strings
# Zanata does not support inner elements in <source>, so we hack these special elements
# This regex translate the Angular elements to special entities (that we will reconvert on pull)
#sed -i 's/<x id=\(.\+\?\)\/>/\<x id=\1\/\>/g' src/locale/source/messages_en_US.xml
-perl -pi -e 's|<x id=(.+?)/>|<x id=\1/>|g' src/locale/source/messages_en_US.xml
\ No newline at end of file
+perl -pi -e 's|<x id=(.+?)/>|<x id=\1/>|g' src/locale/source/messages_en_US.xml
+
+# Add our strings too
+cd ../
+npm run i18n:create-custom-files
\ No newline at end of file
#sed -i 's/\<x id=\(.\+\?\)\/\>/<x id=\1\/>/g' client/src/locale/target/*
for i in 1 2 3; do
- perl -pi -e 's|<x id=(.+?)/>([^"])|<x id=\1/>\2|g' client/src/locale/target/*
-done
\ No newline at end of file
+ perl -pi -e 's|<x id=(.+?)/>([^"])|<x id=\1/>\2|g' client/src/locale/target/*.xml
+done
+
+npm run i18n:xliff2json
\ No newline at end of file
--- /dev/null
+import * as xliff12ToJs from 'xliff/xliff12ToJs'
+import { readFileSync, writeFile } from 'fs'
+import { join } from 'path'
+
+// First, the player
+const playerSource = join(__dirname, '../../../client/src/locale/target/player_fr.xml')
+const playerTarget = join(__dirname, '../../../client/src/locale/target/player_fr.json')
+
+// Remove the two first lines our xliff module does not like
+let playerFile = readFileSync(playerSource).toString()
+playerFile = removeFirstLine(playerFile)
+playerFile = removeFirstLine(playerFile)
+
+xliff12ToJs(playerFile, (err, res) => {
+ if (err) {
+ console.error(err)
+ process.exit(-1)
+ }
+
+ const json = createJSONString(res)
+ writeFile(playerTarget, json, err => {
+ if (err) {
+ console.error(err)
+ process.exit(-1)
+ }
+
+ process.exit(0)
+ })
+})
+
+function removeFirstLine (str: string) {
+ return str.substring(str.indexOf('\n') + 1)
+}
+
+function createJSONString (obj: any) {
+ const res: any = {}
+ const strings = obj.resources['']
+
+ Object.keys(strings).forEach(k => res[k] = strings[k].target)
+
+ return JSON.stringify(res)
+}
set -eu
+# Copy locales
+mkdir -p "./client/dist"
+rm -r "./client/dist/locale"
+cp -r "./client/src/locale/target" "./client/dist/locale"
+
NODE_ENV=test concurrently -k \
"npm run tsc -- --sourceMap && npm run nodemon -- --delay 2 --watch ./dist dist/server" \
"npm run tsc -- --sourceMap --preserveWatchOutput -w"
clientsRouter.use('/client', express.static(distPath, { maxAge: STATIC_MAX_AGE }))
clientsRouter.use('/client/assets/images', express.static(assetsImagesPath, { maxAge: STATIC_MAX_AGE }))
+clientsRouter.use('/client/locales/:locale/:file.json', function (req, res) {
+ if (req.params.locale === 'fr' && req.params.file === 'player') {
+ return res.sendFile(join(__dirname, '../../../client/dist/locale/player_fr.json'))
+ }
+
+ return res.sendStatus(404)
+})
+
// 404 for static files not found
clientsRouter.use('/client/*', (req: express.Request, res: express.Response, next: express.NextFunction) => {
res.sendStatus(404)
return 'en-US'
}
+export function isDefaultLocale (locale: string) {
+ return locale === getDefaultLocale()
+}
+
const possiblePaths = Object.keys(I18N_LOCALES).map(l => '/' + l)
export function is18nPath (path: string) {
return possiblePaths.indexOf(path) !== -1
version "0.1.4"
resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f"
+xliff@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/xliff/-/xliff-3.0.1.tgz#ea0f5840011727aecbddf111e5c26d8590dcca9b"
+ dependencies:
+ xml-js "1.6.2"
+
+xml-js@1.6.2:
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.2.tgz#4c4cb8413998f73701a202a1b8b2f17c985a72c5"
+ dependencies:
+ sax "^1.2.4"
+
xml-name-validator@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"