From 8afc19a6121569da054462c7cb351a3f13030a32 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 28 Jun 2018 13:59:48 +0200 Subject: [PATCH] Add ability to choose the language --- client/src/app/app.component.html | 4 +- client/src/app/app.component.scss | 11 -- client/src/app/app.module.ts | 2 + .../app/menu/language-chooser.component.html | 15 +++ .../app/menu/language-chooser.component.scss | 15 +++ .../app/menu/language-chooser.component.ts | 32 +++++ client/src/app/menu/menu.component.html | 126 ++++++++++-------- client/src/app/menu/menu.component.scss | 47 ++++++- client/src/app/menu/menu.component.ts | 10 +- client/src/assets/images/menu/language.png | Bin 0 -> 10937 bytes client/src/sass/application.scss | 2 +- client/src/sass/include/_variables.scss | 2 + package.json | 1 + server.ts | 3 + server/controllers/client.ts | 37 +++-- shared/models/i18n/i18n.ts | 7 +- yarn.lock | 7 + 17 files changed, 231 insertions(+), 90 deletions(-) create mode 100644 client/src/app/menu/language-chooser.component.html create mode 100644 client/src/app/menu/language-chooser.component.scss create mode 100644 client/src/app/menu/language-chooser.component.ts create mode 100644 client/src/assets/images/menu/language.png diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index e50546633..09b2c15be 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html @@ -18,9 +18,7 @@
-
- -
+
diff --git a/client/src/app/app.component.scss b/client/src/app/app.component.scss index 6edf966f9..9eca31320 100644 --- a/client/src/app/app.component.scss +++ b/client/src/app/app.component.scss @@ -9,17 +9,6 @@ margin-top: $header-height; } -.title-menu-left { - position: fixed; - height: calc(100vh - #{$header-height}); - padding: 0; - width: $menu-width; - - .title-menu-left-block.menu { - height: 100%; - } -} - .header { height: $header-height; position: fixed; diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index 9cffdd31e..48886fd4e 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts @@ -17,6 +17,7 @@ import { SignupModule } from './signup' import { VideosModule } from './videos' import { buildFileLocale, getCompleteLocale, isDefaultLocale } from '../../../shared/models/i18n' import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils' +import { LanguageChooserComponent } from '@app/menu/language-chooser.component' export function metaFactory (serverService: ServerService): MetaLoader { return new MetaStaticLoader({ @@ -36,6 +37,7 @@ export function metaFactory (serverService: ServerService): MetaLoader { AppComponent, MenuComponent, + LanguageChooserComponent, HeaderComponent ], imports: [ diff --git a/client/src/app/menu/language-chooser.component.html b/client/src/app/menu/language-chooser.component.html new file mode 100644 index 000000000..f941e32f8 --- /dev/null +++ b/client/src/app/menu/language-chooser.component.html @@ -0,0 +1,15 @@ + diff --git a/client/src/app/menu/language-chooser.component.scss b/client/src/app/menu/language-chooser.component.scss new file mode 100644 index 000000000..4574f78c6 --- /dev/null +++ b/client/src/app/menu/language-chooser.component.scss @@ -0,0 +1,15 @@ +@import '_variables'; +@import '_mixins'; + +.modal-title { + text-align: center; +} + +.modal-body { + text-align: center; + + a { + font-size: 16px; + margin-top: 10px; + } +} \ No newline at end of file diff --git a/client/src/app/menu/language-chooser.component.ts b/client/src/app/menu/language-chooser.component.ts new file mode 100644 index 000000000..3de6a129d --- /dev/null +++ b/client/src/app/menu/language-chooser.component.ts @@ -0,0 +1,32 @@ +import { Component, ViewChild } from '@angular/core' +import { ModalDirective } from 'ngx-bootstrap/modal' +import { I18N_LOCALES } from '../../../../shared' + +@Component({ + selector: 'my-language-chooser', + templateUrl: './language-chooser.component.html', + styleUrls: [ './language-chooser.component.scss' ] +}) +export class LanguageChooserComponent { + @ViewChild('modal') modal: ModalDirective + + languages: { [ id: string ]: string }[] = [] + + constructor () { + this.languages = Object.keys(I18N_LOCALES) + .map(k => ({ id: k, label: I18N_LOCALES[k] })) + } + + show () { + this.modal.show() + } + + hide () { + this.modal.hide() + } + + buildLanguageLink (lang: { id: string }) { + return window.location.origin + '/' + lang.id + } + +} diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html index 8e3b295f7..784b5cd85 100644 --- a/client/src/app/menu/menu.component.html +++ b/client/src/app/menu/menu.component.html @@ -1,70 +1,82 @@ - - - + \ No newline at end of file diff --git a/client/src/app/menu/menu.component.scss b/client/src/app/menu/menu.component.scss index c36a7aa36..e61f4acd3 100644 --- a/client/src/app/menu/menu.component.scss +++ b/client/src/app/menu/menu.component.scss @@ -1,6 +1,13 @@ @import '_variables'; @import '_mixins'; +.menu-wrapper { + position: fixed; + height: calc(100vh - #{$header-height}); + padding: 0; + width: $menu-width; +} + menu { background-color: $black-background; margin: 0; @@ -11,6 +18,13 @@ menu { overflow: hidden; z-index: 1000; color: $menu-color; + overflow-y: auto; + display: flex; + flex-direction: column; + + .top-menu { + flex-grow: 1; + } .logged-in-block { height: 100px; @@ -100,7 +114,7 @@ menu { a { display: flex; align-items: center; - padding-left: 26px; + padding-left: $menu-left-padding; color: $menu-color; cursor: pointer; height: 40px; @@ -155,4 +169,35 @@ menu { } } } + + .footer { + margin-bottom: 15px; + padding-left: $menu-left-padding; + + .language { + display: inline-block; + color: $menu-bottom-color; + cursor: pointer; + font-size: 12px; + font-weight: $font-semibold; + + .icon { + @include icon(28px); + opacity: 0.9; + + &.icon-language { + position: relative; + top: -1px; + width: 28px; + height: 24px; + + background-image: url('../../assets/images/menu/language.png'); + } + + &:hover { + opacity: 1; + } + } + } + } } diff --git a/client/src/app/menu/menu.component.ts b/client/src/app/menu/menu.component.ts index c0aea89b3..dded6b4d5 100644 --- a/client/src/app/menu/menu.component.ts +++ b/client/src/app/menu/menu.component.ts @@ -1,8 +1,8 @@ -import { Component, OnInit } from '@angular/core' -import { Router } from '@angular/router' +import { Component, OnInit, ViewChild } from '@angular/core' import { UserRight } from '../../../../shared/models/users/user-right.enum' import { AuthService, AuthStatus, RedirectService, ServerService } from '../core' import { User } from '../shared/users/user.model' +import { LanguageChooserComponent } from '@app/menu/language-chooser.component' @Component({ selector: 'my-menu', @@ -10,6 +10,8 @@ import { User } from '../shared/users/user.model' styleUrls: [ './menu.component.scss' ] }) export class MenuComponent implements OnInit { + @ViewChild('languageChooserModal') languageChooserModal: LanguageChooserComponent + user: User isLoggedIn: boolean userHasAdminAccess = false @@ -90,6 +92,10 @@ export class MenuComponent implements OnInit { this.redirectService.redirectToHomepage() } + openLanguageChooser () { + this.languageChooserModal.show() + } + private computeIsUserHasAdminAccess () { const right = this.getFirstAdminRightAvailable() diff --git a/client/src/assets/images/menu/language.png b/client/src/assets/images/menu/language.png new file mode 100644 index 0000000000000000000000000000000000000000..60e6fec00fd20a3beae24b37729d8f16d1d7d476 GIT binary patch literal 10937 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 { +clientsRouter.use('' + + '/videos/embed', (req: express.Request, res: express.Response, next: express.NextFunction) => { res.sendFile(embedPath) }) @@ -63,7 +70,7 @@ clientsRouter.use('/client/*', (req: express.Request, res: express.Response, nex // Try to provide the right language index.html clientsRouter.use('/(:language)?', function (req, res) { if (req.accepts(ACCEPT_HEADERS) === 'html') { - return res.sendFile(getIndexPath(req, req.params.language)) + return res.sendFile(getIndexPath(req, res, req.params.language)) } return res.status(404).end() @@ -77,16 +84,24 @@ export { // --------------------------------------------------------------------------- -function getIndexPath (req: express.Request, paramLang?: string) { +function getIndexPath (req: express.Request, res: express.Response, paramLang?: string) { let lang: string // Check param lang validity if (paramLang && is18nLocale(paramLang)) { lang = paramLang + + // Save locale in cookies + res.cookie('clientLanguage', lang, { + secure: CONFIG.WEBSERVER.SCHEME === 'https', + sameSite: true, + maxAge: 1000 * 3600 * 24 * 90 // 3 months + }) + + } else if (req.cookies.clientLanguage && is18nLocale(req.cookies.clientLanguage)) { + lang = req.cookies.clientLanguage } else { - // lang = req.acceptsLanguages(POSSIBLE_LOCALES) || getDefaultLocale() - // Disable auto language for now - lang = getDefaultLocale() + lang = req.acceptsLanguages(POSSIBLE_LOCALES) || getDefaultLocale() } return join(__dirname, '../../../client/dist/' + buildFileLocale(lang) + '/index.html') @@ -181,18 +196,18 @@ async function generateWatchHtmlPage (req: express.Request, res: express.Respons } else if (validator.isInt(videoId)) { videoPromise = VideoModel.loadAndPopulateAccountAndServerAndTags(+videoId) } else { - return res.sendFile(getIndexPath(req)) + return res.sendFile(getIndexPath(req, res)) } let [ file, video ] = await Promise.all([ - readFileBufferPromise(getIndexPath(req)), + readFileBufferPromise(getIndexPath(req, res)), videoPromise ]) const html = file.toString() // Let Angular application handle errors - if (!video || video.privacy === VideoPrivacy.PRIVATE) return res.sendFile(getIndexPath(req)) + if (!video || video.privacy === VideoPrivacy.PRIVATE) return res.sendFile(getIndexPath(req, res)) const htmlStringPageWithTags = addOpenGraphAndOEmbedTags(html, video) res.set('Content-Type', 'text/html; charset=UTF-8').send(htmlStringPageWithTags) diff --git a/shared/models/i18n/i18n.ts b/shared/models/i18n/i18n.ts index e2b440900..14b02a01d 100644 --- a/shared/models/i18n/i18n.ts +++ b/shared/models/i18n/i18n.ts @@ -1,8 +1,8 @@ export const LOCALE_FILES = [ 'player', 'server' ] export const I18N_LOCALES = { - 'en-US': 'English (US)', - 'fr-FR': 'Français (France)' + 'en-US': 'English', + 'fr-FR': 'Français' } const I18N_LOCALE_ALIAS = { @@ -13,8 +13,6 @@ const I18N_LOCALE_ALIAS = { 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' } @@ -23,6 +21,7 @@ export function isDefaultLocale (locale: string) { return getCompleteLocale(locale) === getCompleteLocale(getDefaultLocale()) } +const possiblePaths = POSSIBLE_LOCALES.map(l => '/' + l) export function is18nPath (path: string) { return possiblePaths.indexOf(path) !== -1 } diff --git a/yarn.lock b/yarn.lock index 65b78b4fa..8c79ab282 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1590,6 +1590,13 @@ content-type@~1.0.1, content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" +cookie-parser@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.4.3.tgz#0fe31fa19d000b95f4aadf1f53fdc2b8a203baa5" + dependencies: + cookie "0.3.1" + cookie-signature "1.0.6" + cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" -- 2.25.1