diff --git a/.eslintrc.json b/.eslintrc.json index 40ad1516..b6a9a159 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,6 +4,11 @@ "extends": [], "globals": {}, "plugins": [], - "ignorePatterns": ["node_modules/", "dist/", "webpack.config.js", "build/", "vendor/"], + "ignorePatterns": [ + "node_modules/", "dist/", "webpack.config.js", + "build/", + "vendor/", + "support/documentation", + "build-*js"], "rules": {} } diff --git a/CHANGELOG.md b/CHANGELOG.md index d86aa0ab..07460231 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## ??? (Not Released Yet) +### New Features + +* Settings page translations. For now: english and french are available. + ### Minor changes and fixes * Updating a link to the documentation in the settings page. diff --git a/build-languages.js b/build-languages.js new file mode 100644 index 00000000..21991364 --- /dev/null +++ b/build-languages.js @@ -0,0 +1,154 @@ +/** + * This script is used to build the translations files. + * + * Indeed, some strings used in plugin settings are not easy to write + * in JSON format (contains html, double quotes, line breaks, ...). + * So we use YAML files to translates these strings, + * including the english version. + * + * This scripts takes the standard JSON files, the YAML translation files, + * and mixes everything up in dist/languages/xx.json. + */ +const fs = require('fs') +const path = require('path') +const YAML = require('yaml') + +class BuildLanguages { + destinationDir = null + langs = [] + translationsStrings = {} + monoLingualReferences = {} + + constructor () { + this.destinationDir = path.resolve(__dirname, 'dist', 'languages') + } + + async generateFiles () { + await this.loadLangs() + await this.initTranslationStrings() + await this.readJSONTranslations() + await this.readSettingsTranslations() + + await this.ensureDestinationDir() + await this.writeJSONTranslations() + await this.writeMonoLingualReferences() + } + + loadLangs () { + const packagejson = require('./package.json') + const translations = packagejson.translations || {} + this.langs = Object.values(translations).map(filename => { + return filename.match(/^.*\/(\w+)\.json$/)[1] + }) + console.log('Existings languages: ', this.langs) + } + + initTranslationStrings () { + console.log('Initializing translations strings...') + const translationsStrings = {} + for (const l of this.langs) { + translationsStrings[l] = {} + } + this.translationsStrings = translationsStrings + } + + async readJSONTranslations () { + console.log('Reading standard JSON translation strings...') + const translationsStrings = this.translationsStrings + for (const l of this.langs) { + const filePath = path.resolve(__dirname, 'languages', l + '.json') + if (!fs.existsSync(filePath)) { + console.warn(`File ${filePath} missing, ignoring.`) + continue + } + const t = require(filePath) + for (const k in t) { + const v = t[k] + if (k in translationsStrings[l]) { + throw new Error(`Duplicate translation for key ${k} in lang ${l}.`) + } + translationsStrings[l][k] = v + } + } + } + + async readSettingsTranslations () { + console.log('Reading Settings Yaml translation strings...') + + // First we must get the english reference file, + // that will give us the keys to use in final JSON. + + const reference = await this.getYmlFileContent(path.resolve(__dirname, 'languages', 'settings', 'en.yml')) + this.monoLingualReferences['settings'] = reference + + const translationsStrings = this.translationsStrings + for (const l of this.langs) { + const filePath = path.resolve(__dirname, 'languages', 'settings', l + '.yml') + const o = await this.getYmlFileContent(filePath) + + for (const k in o) { + if (!(k in reference)) { + throw new Error(`File ${filePath} contains unknown keys. Key=${k}.`) + } + const newKey = reference[k] + this.translationsStrings[l][newKey] = o[k] + } + } + } + + async getYmlFileContent (filePath) { + if (!fs.existsSync(filePath)) { + console.warn(`File ${filePath} missing, ignoring.`) + return {} + } + + const content = await fs.promises.readFile(filePath, 'utf8') + const o = YAML.parse(content) || {} + for (const k in o) { + let v = o[k] + if (v === null) { + // this value is ok! + continue + } + if ((typeof v) !== 'string') { + throw new Error(`File ${filePath} contains strings that are not strings! Key=${k}`) + } + + // We are normalizing the string, to avoid problems. + // As it is supposed to be html, we will strip newlines and multiple adjacent spaces. + v = v.replace(/\n/g, ' ') + v = v.replace(/\s\s+/g, ' ') + v = v.trim() + o[k] = v + } + return o + } + + async ensureDestinationDir () { + if (!fs.existsSync(this.destinationDir)) { + await fs.promises.mkdir(this.destinationDir) + } + } + + async writeJSONTranslations () { + console.log('Writing JSON files...') + for (const l of this.langs) { + const filePath = path.resolve(this.destinationDir, l + '.json') + await fs.promises.writeFile(filePath, JSON.stringify(this.translationsStrings[l])) + } + } + + async writeMonoLingualReferences () { + console.log('Writing JSON reference files...') + for (const name in this.monoLingualReferences) { + const filePath = path.resolve(this.destinationDir, name + '.reference.json') + await fs.promises.writeFile(filePath, JSON.stringify(this.monoLingualReferences[name])) + } + } +} + +const bl = new BuildLanguages() +bl.generateFiles().then(() => {}, (err) => { + console.error(err) + throw err +}) diff --git a/client/admin-plugin-client-plugin.ts b/client/admin-plugin-client-plugin.ts index e74cc51d..6dcc4bde 100644 --- a/client/admin-plugin-client-plugin.ts +++ b/client/admin-plugin-client-plugin.ts @@ -99,14 +99,13 @@ function register ({ registerHook, registerSettingsScript, peertubeHelpers }: Re const table = document.createElement('table') table.classList.add('peertube-plugin-livechat-prosody-list-rooms') container.append(table) - // TODO: translate labels. const labels: any = { - RoomName: 'Room name', - RoomDescription: 'Room description', - NotFound: 'Not found', - Video: 'Video', - Channel: 'Channel', - LastActivity: 'Last activity' + RoomName: await peertubeHelpers.translate('Room name'), + RoomDescription: await peertubeHelpers.translate('Room description'), + NotFound: await peertubeHelpers.translate('Not found'), + Video: await peertubeHelpers.translate('Video'), + Channel: await peertubeHelpers.translate('Channel'), + LastActivity: await peertubeHelpers.translate('Last activity') } const titleLineEl = document.createElement('tr') diff --git a/languages/ca.json b/languages/ca.json index a27a0379..0e168c55 100644 --- a/languages/ca.json +++ b/languages/ca.json @@ -15,5 +15,11 @@ "Open": false, "Use current theme colors": false, "Generate an iframe to embed the chat in a website": false, - "Chat for live stream": false + "Chat for live stream": false, + "Room name": false, + "Room description": false, + "Not found": false, + "Video": false, + "Channel": false, + "Last activity": false } diff --git a/languages/de.json b/languages/de.json index 8d3e5580..f9dd09a2 100644 --- a/languages/de.json +++ b/languages/de.json @@ -15,5 +15,11 @@ "Open": "Öffnen", "Use current theme colors": "Die derzeitigen Themenfarben nutzen", "Generate an iframe to embed the chat in a website": "IFrame-Element erstellen, um den Chat in eine Webseite zu integrieren", - "Chat for live stream": "Chat für den Livestream" + "Chat for live stream": "Chat für den Livestream", + "Room name": false, + "Room description": false, + "Not found": false, + "Video": false, + "Channel": false, + "Last activity": false } diff --git a/languages/eo.json b/languages/eo.json index 98c4c540..50d043d8 100644 --- a/languages/eo.json +++ b/languages/eo.json @@ -15,5 +15,11 @@ "Open": "Malfermi", "Use current theme colors": "Uzi koloroj el la nuna etoso", "Generate an iframe to embed the chat in a website": false, - "Chat for live stream": false + "Chat for live stream": false, + "Room name": false, + "Room description": false, + "Not found": false, + "Video": false, + "Channel": false, + "Last activity": false } diff --git a/languages/es.json b/languages/es.json index 9ed3bf5b..a59723fd 100644 --- a/languages/es.json +++ b/languages/es.json @@ -15,5 +15,11 @@ "Open": "Abrir", "Use current theme colors": "Utilizar los colores del tema actual", "Generate an iframe to embed the chat in a website": false, - "Chat for live stream": false + "Chat for live stream": false, + "Room name": false, + "Room description": false, + "Not found": false, + "Video": false, + "Channel": false, + "Last activity": false } diff --git a/languages/eu.json b/languages/eu.json index b275b0f6..e1e84e47 100644 --- a/languages/eu.json +++ b/languages/eu.json @@ -15,5 +15,11 @@ "Open": "Ireki", "Use current theme colors": "Erabili uneko itxuraren koloreak", "Generate an iframe to embed the chat in a website": false, - "Chat for live stream": false + "Chat for live stream": false, + "Room name": false, + "Room description": false, + "Not found": false, + "Video": false, + "Channel": false, + "Last activity": false } diff --git a/languages/fr.json b/languages/fr.json index af3c565e..99bee396 100644 --- a/languages/fr.json +++ b/languages/fr.json @@ -15,5 +15,11 @@ "Open": "Ouvrir", "Use current theme colors": "Utiliser les couleurs du thème courant", "Generate an iframe to embed the chat in a website": "Générer une iframe pour intégrer le tchat dans un site web", - "Chat for live stream:": "Tchat pour le direct :" + "Chat for live stream:": "Tchat pour le direct :", + "Room name": "Nom du salon", + "Room description": "Description du salon", + "Not found": "Non trouvé", + "Video": "Vidéo", + "Channel": "Chaîne", + "Last activity": "Dernière activité" } diff --git a/languages/it.json b/languages/it.json index 46389476..7e7173bf 100644 --- a/languages/it.json +++ b/languages/it.json @@ -15,5 +15,11 @@ "Open": false, "Use current theme colors": false, "Generate an iframe to embed the chat in a website": false, - "Chat for live stream": false + "Chat for live stream": false, + "Room name": false, + "Room description": false, + "Not found": false, + "Video": false, + "Channel": false, + "Last activity": false } diff --git a/languages/ja.json b/languages/ja.json index 785f64ca..cd9edf38 100644 --- a/languages/ja.json +++ b/languages/ja.json @@ -15,5 +15,11 @@ "Open": "開く", "Use current theme colors": "現在のテーマカラーを使用する", "Generate an iframe to embed the chat in a website": false, - "Chat for live stream": false + "Chat for live stream": false, + "Room name": false, + "Room description": false, + "Not found": false, + "Video": false, + "Channel": false, + "Last activity": false } diff --git a/languages/oc.json b/languages/oc.json index 206b74a5..e50d2e31 100644 --- a/languages/oc.json +++ b/languages/oc.json @@ -15,5 +15,11 @@ "Open": "Dobrir", "Use current theme colors": "Utilizar las colors del tèma actual" , "Generate an iframe to embed the chat in a website": false, - "Chat for live stream": false + "Chat for live stream": false, + "Room name": false, + "Room description": false, + "Not found": false, + "Video": false, + "Channel": false, + "Last activity": false } diff --git a/languages/pl.json b/languages/pl.json index 08f4b369..0261be87 100644 --- a/languages/pl.json +++ b/languages/pl.json @@ -15,5 +15,11 @@ "Open": false, "Use current theme colors": false, "Generate an iframe to embed the chat in a website": false, - "Chat for live stream": false + "Chat for live stream": false, + "Room name": false, + "Room description": false, + "Not found": false, + "Video": false, + "Channel": false, + "Last activity": false } diff --git a/languages/settings/en.yml b/languages/settings/en.yml new file mode 100644 index 00000000..d46c0482 --- /dev/null +++ b/languages/settings/en.yml @@ -0,0 +1,186 @@ +important_note_title: "

Important notes

" +important_note_text: | + You can find the plugin documentation here: + + Peertube Plugin Livechat documentation + . + +diagnostic: | + Before asking for help, please use the diagnostic tool: + Launch diagnostic + (if this button is not opening a new window, please try to refresh the page). + +chat_title: "

Chat

" + +list_rooms_label: "List existing rooms" +list_rooms_description: | + List rooms + +chat_behaviour_description: "

Chat behaviour

" + +room_type_label: "Room type" +room_type_description: "You can choose here to have separate rooms for each video, or to group them by channel." +room_type_option_video: "Each video has its own webchat room" +room_type_option_channel: "Webchat rooms are grouped by channel" + +auto_display_label: "Automatically open the chat" +auto_display_description: "When watching a video, the chatbox will automatically open." + +open_blank_label: "Show the «open in new window» button" +open_blank_description: "There will be a button for opening the web chat in a new window." + +share_url_label: "Show the «share chat link» button" +share_url_description: "There will be a button for sharing a chat url (could be used to intregrated in OBS for example)." +share_url_option_nobody: "Show for nobody" +share_url_option_everyone: "Show for everyone" +share_url_option_owner: "Show for the video owner" +share_url_option_owner_moderators: "Show for the video owner and instance's moderators" + +per_live_video_label: "Users can activate the chat for their lives" +per_live_video_description: "If checked, all live videos will have a checkbox in their properties for enabling the web chat." + +per_live_video_warning_description: | + + You have enabled the setting «Users can activate the chat for their lives». + It is redundant with the «Activate chat for all lives» setting. + + +all_lives_label: "Activate chat for all lives" +all_lives_description: "If checked, the chat will be enabled for all lives." + +all_non_lives_label: "Activate chat for all non-lives" +all_non_lives_description: "If checked, the chat will be enable for all video that are not lives." + +videos_list_label: "Activate chat for these videos" +videos_list_description: | + Videos UUIDs for which we want a web chat. + Can be non-live videos. One per line.
+ You can add comments: everything after the # character will be stripped off, and empty lines ignored.
+ Don't add private videos, the UUIDs will be send to frontend. + +no_anonymous_label: "Hide the chat for anonymous users" +no_anonymous_description: "If checked, anonymous Peertube users won't see the chat." + +theming_advanced_description: "

Theming

" + +converse_theme_label: "ConverseJS theme" +converse_theme_description: "Please choose the converseJS theme you want to use." +converse_theme_option_peertube: "Peertube theme" +converse_theme_option_default: "Default ConverseJS theme" +converse_theme_option_concord: "ConverseJS concord theme" + +autocolors_label: "Automatic color detection" +autocolors_description: | + Try to auto detect colors from user's current theme.
+ When this settings is enabled, the plugin tries to auto-detect colors to apply to the chat theme.
+ If this is not correctly working for some of your Peertube theme, you can disable this option. + You can report the bug on the official + + issue tracker + . Don't forget to specify which theme is not working.` + +chat_style_label: "Webchat iframe style attribute" +chat_style_description: | + Additional styles to be added on the iframe style attribute.
+ Example: height:400px; + +prosody_advanced_description: "

Chat server advanced settings

" + +help_builtin_prosody_label: "Prosody server" +help_builtin_prosody_description: | + This plugin uses the Prosody XMPP server to handle chat rooms.
+ This plugin comes with a Prosody AppImage, that will be used to run the service. + +system_prosody_label: "Use system Prosody" +system_prosody_description: | + Warning: don't check this settings if you are not sure of what you are doing.
+ By checking this settings, your Peertube will use the Prosody server that comes with your system, + and not the embeded AppImage.
+ Only use this if you encounter problems with the embedded Prosody. + +disable_websocket_label: "Disable Websocket" +disable_websocket_description: | + With Peertube >= 5.0.0, this plugin try to use Websocket connection for chatting. + If the user's browser or connection is not compatible, the browser will automatically fallback on the BOSH protocol. +
+ But in rare case, this can fail. For example if you have a reverse proxy in front of Peertube that does not + allow Websocket connection for plugins. + In this case, you can check this settings to disable Websocket connections. + +prosody_port_label: "Prosody port" +prosody_port_description: | + The port that will be used by the Prosody server.
+ Change it if this port is already in use on your server.
+ You can close this port on your firewall, it will not be accessed from the outer world.
+ Note: this might change in a near feature, as it is planned to add feature to activate external connections. + +prosody_peertube_uri_label: "Peertube url for API calls" +prosody_peertube_uri_description: | + Please let this settings empty if you don't know what you are doing.
+ In some rare case, Prosody can't call Peertube's API from its public URI. + You can use this field to customise Peertube's URI for Prosody modules + (for example with «http://localhost:9000» or «http://127.0.0.1:9000»). + +prosody_muc_log_by_default_label: "Log rooms content by default" +prosody_muc_log_by_default_description: | + If checked, room contents will be saved by default. + Any user that join a room will see what was written before he joins.
+ Please note that it is always possible to enable/disable the content + archiving for a specific room, by editing its properties. + +prosody_muc_expiration_label: "Room logs expiration" +prosody_muc_expiration_description: | + You can choose here how long the chatting room's content is kept by the server. The value can be: + + +prosody_c2s_label: "Enable client to server connections" +prosody_c2s_description: | + Enable XMPP clients to connect to the builtin Prosody server.
+ This option alone only allows connections from localhost clients. + +prosody_c2s_port_label: "Prosody client to server port" +prosody_c2s_port_description: | + The port that will be used by the c2s module of the builtin Prosody server.
+ XMPP clients shall use this port to connect.
+ Change it if this port is already in use on your server.
+ You can keep this port closed on your firewall for now, it will not be accessed from the outer world.
+ Note: this might change in a near feature, as it is planned to add feature to activate external connections. + +prosody_components_label: "Enable custom Prosody external components" +prosody_components_description: | + Enable the use of external XMPP components.
+ This option alone only allows connections from localhost.
+ This feature can for example be used to connect some bots to the chatting rooms. + +prosody_components_port_label: "Prosody external components port" +prosody_components_port_description: | + The port that will be used by XMPP components to connect to the Prosody server.
+ Change it if this port is already in use on your server.
+ You can keep this port closed on your firewall for now, it will not be accessed from the outer world.
+ Note: this might change in a near feature, as it is planned to add feature to activate external connections. + +prosody_components_list_label: "External components" +prosody_components_list_description: | + The external components to declare: + diff --git a/languages/settings/fr.yml b/languages/settings/fr.yml new file mode 100644 index 00000000..9979cbc1 --- /dev/null +++ b/languages/settings/fr.yml @@ -0,0 +1,204 @@ +important_note_title: "

Note importante

" +important_note_text: | + Vous pouvez trouver la documentation du plugin ici: + + Documentation du Plugin Peertube Livechat + . + +diagnostic: | + Avant de demander de l'aide, merci d'utiliser l'outils de diagnostic: + Lancer le diagnostique + (si ce bouton n'ouvre pas une nouvelle fenêtre, merci d'essayer de raffraichir la page). + +chat_title: "

Tchat

" + +list_rooms_label: "Lister les salons de tchat existants" +list_rooms_description: | + Lister les salons + +chat_behaviour_description: "

Comportement du tchat

" + +room_type_label: "Type de salon" +room_type_description: "Vous pouvez choisir d'avoir des salons séparés pour chaque vidéo, ou de les grouper par chaîne." +room_type_option_video: "Chaque video a son propre salon de discussion" +room_type_option_channel: "Les salons sont regroupés par chaîne" + +auto_display_label: "Ouvrir automatiquement le tchat" +auto_display_description: "Quand on regarde une vidéo, le tchat va s'ouvrir automatiquement." + +open_blank_label: "Montrer le bouton «ouvrir dans une nouvelle fenêtre»" +open_blank_description: "Il y aura un bouton pour ouvrir le tchat dans une nouvelle fenêtre." + +share_url_label: "Montrer le bouton «partager le lien du salon»" +share_url_description: "Il y aura un bouton permettant de partager le lien vers le tchat (peut par exemple être utilisé pour l'intégration dans OBS)." +share_url_option_nobody: "Ne pas le montrer" +share_url_option_everyone: "Le montrer à tout le monde" +share_url_option_owner: "Le montrer au proriétaire de la vidéo" +share_url_option_owner_moderators: "Le montrer au propriétaire de la vidéo, et aux modérateur⋅rices de l'instance" + +per_live_video_label: "Les utilisateur⋅rices peuvent activer le tchat pour leurs directs" +per_live_video_description: "Si coché, il y aura pour tous les directs une case à cocher dans les propriétés qui permettra d'activer/désactiver le tchat." + +per_live_video_warning_description: | + + Vous avez activé le paramètre «Les utilisateur⋅rices peuvent activer le tchat pour leurs directs». + C'est redondant avec «Activer le tchat pour tous les directs». + + +all_lives_label: "Activer le tchat pour tous les directs" +all_lives_description: "Si coché, il y aura un tchat pour tous les directs." + +all_non_lives_label: "Activer le tchat pour toutes les vidéos «non-direct»" +all_non_lives_description: "Si coché, il y aura un tchat pour toutes les vidéos qui ne sont pas des directs." + +videos_list_label: "Activer le tchat pour ces vidéos" +videos_list_description: | + Mettez ici les UUIDs des vidéos pour lequelles vous voulez forcer l'activation + du tchat. + Cela peut être des directs, ou non. + Un UUID par ligne.
+ Vous pouvez ajouter des commentaires: tout ce qui se trouve après le caractère # + sera retiré, et les lignes vides ignorées.
+ N'ajoutez pas de vidéos privées, les UUIDs fuiteraient. + +no_anonymous_label: "Masque les tchats pour les utilisateur⋅rices anonymes" +no_anonymous_description: "Si coché, les utilisteur⋅rices non connecté⋅es ne verront pas les tchats." + +theming_advanced_description: "

Personnalisation des thèmes

" + +converse_theme_label: "Thème ConverseJS" +converse_theme_description: "Merci de choisir le thème ConverseJS que vous voulez utiliser." +converse_theme_option_peertube: "Thème Peertube" +converse_theme_option_default: "Thème par défaut de ConverseJS" +converse_theme_option_concord: "Thème concord de ConverseJS" + +autocolors_label: "Détection automatique des couleurs" +autocolors_description: | + Essaie de détecter automatiquement les couleurs du thème courant de l'utilisateur⋅rice. +
+ Quand ce paramètre est activé, le plugin essaie de détecter automatiquement les + couleurs à appliquer au thème du tchat. +
+ Si cela ne fonctionne pas correctement pour certains de vos thèmes Peertube, + vous pouvez désactiver cette option. + Vous pouvez rapporter les bugs sur le + gestionnaire de ticket + . N'oubliez pas de préciser pour quel thème cela ne fonctionne pas. + +chat_style_label: "Attribut de style de l'iframe du tchat" +chat_style_description: | + Styles additionnels à appliquer sur l'iframe du tchat.
+ Exemple: height:400px; + +prosody_advanced_description: "

Paramètres avancés du serveur de tchat

" + +help_builtin_prosody_label: "Serveur Prosody" +help_builtin_prosody_description: | + Ce plugin utilise le serveur XMPP Prosody pour gérer les salons de discussion.
+ Ce plugin inclu une AppImage de Prosody, qui va être utilisée pour faire tourner le service. + +system_prosody_label: "Utiliser le serveur Prosody installé sur le système" +system_prosody_description: | + Attention: ne cocher pas ce paramètre si vous n'êtes pas sûr de ce que vous faites.
+ En cochant ce paramètre, Peertube va utiliser l'exécutable Prosody fourni + par le système, et non l'AppImage intégrée.
+ N'utiliser cette option que si vous rencontrez des problèmes pour utiliser l'AppImage intégrée. + +disable_websocket_label: "Désactiver Websocket" +disable_websocket_description: | + Avec Peertube >= 5.0.0, ce plugin va essayer d'utiliser Websocket pour les connections au tchat. + Si le navigateur de l'utilisateur⋅rice ou sa connection n'est pas compatible, le navigateur va + automatiquement passer au protocole BOSH. +
+ Mais dans de rare cas, ça pourrait échouer. Par exemple si vous avez un reverse proxy devant votre Peertube + qui ne permettrait pas les connection Websocket. + Dans ce cas, vous pouvez cocher cette option pour désactiver les connections Websocket. + +prosody_port_label: "Port Prosody" +prosody_port_description: | + Le port qui va être utilisé par le serveur Prosody.
+ Changer le si ce port est déjà utilisé sur votre serveur.
+ Vous pouvez fermer ce port sur votre pare-feu, il ne sera pas accéder par le monde extérieur.
+ Note: cela pourrait changer dans un futur proche, car il est prévu d'ajouter des paramètres pour autoriser les connections externes. + +prosody_peertube_uri_label: "Url Peertube pour les appels d'API" +prosody_peertube_uri_description: | + Merci de ne pas toucher à ce paramètre si vous ne savez pas ce que vous faites.
+ Dans de rare cas, le serveur Prosody ne peut appeler l'API de Peertube en utilisant l'url publique. + Vous pouvez utiliser ce paramètre pour personnaliser l'url que les modules Prosody utiliseront pour + les API Peertube (par exemple en mettant «http://localhost:9000» ou «http://127.0.0.1:9000»). + +prosody_muc_log_by_default_label: "Enregistrer les salons par défaut" +prosody_muc_log_by_default_description: | + Si coché, le contenu des salons sera enregistré par défaut. + Quand un⋅e utilisateur⋅rice rejoint un salon, iel pourra voir ce qui a été dit avant. +
+ À noter qu'il est toujours possible d'activer/désactiver cette fonctionnalité + pour un salon spécifique, en changeant ses paramètres. + + +prosody_muc_expiration_label: "Expiration des journaux de salon" +prosody_muc_expiration_description: | + Vous pouvez choisir combien de temps le contenu des salons est gardé sur le serveur. + La valeur peut être: + + +prosody_c2s_label: "Activer les connections client vers serveur" +prosody_c2s_description: | + Autoriser les clients XMPP à se connecter au serveur Prosody.
+ Cette option seule n'autorise que les connections de clients sur le localhost. + +prosody_c2s_port_label: "Port Prosody client vers serveur" +prosody_c2s_port_description: | + Le port à utiliser pour les connections XMPP c2s (client to server).
+ Les clients XMPP devront utiliser ce port pour se connecter.
+ Changez ce port si le port est déjà utilisé sur votre serveur.
+ Pour l'instant, vous pouvez garder ce port fermé sur votre pare-feu, + il ne sera pas accessible du monde extérieur (Prosody n'écoute que sur localhost).
+ Note: cela pourrait changer dans un futur proche, car il est prévu d'ajouter des paramètres pour autoriser les connections externes. + +prosody_components_label: "Activer les composants externe personnalisés Prosody" +prosody_components_description: | + Active l'utilisation des «External XMPP components».
+ Cette option seule n'autorise que les connections depuis localhost.
+ Cette fonctionnalité peut par exemple être utilisée pour connecter des bots aux salons. + +prosody_components_port_label: "Port pour les composants externe Prosody" +prosody_components_port_description: | + Le port à utiliser pour les XMPP components.
+ Changez ce port s'il est déjà utilisé sur votre serveur.
+ Pour l'instant, vous pouvez garder ce port fermé sur votre pare-feu, + il ne sera pas accessible du monde extérieur (Prosody n'écoute que sur localhost).
+ Note: cela pourrait changer dans un futur proche, car il est prévu d'ajouter des paramètres pour autoriser les connections externes. + +prosody_components_list_label: "Composants externes" +prosody_components_list_description: | + Les composants externes à déclarer : + diff --git a/package-lock.json b/package-lock.json index c56c2bd4..e11823bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,8 @@ "stylelint-config-recommended-scss": "^5.0.1", "stylelint-config-standard-scss": "^2.0.1", "svgo": "^2.8.0", - "typescript": "^4.3.5" + "typescript": "^4.3.5", + "yaml": "^2.2.1" }, "engines": { "npm": ">=7" @@ -4690,6 +4691,15 @@ "node": ">=10" } }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/cron-parser": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.7.0.tgz", @@ -11504,12 +11514,12 @@ "dev": true }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz", + "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==", "dev": true, "engines": { - "node": ">= 6" + "node": ">= 14" } } }, @@ -15332,6 +15342,14 @@ "parse-json": "^5.0.0", "path-type": "^4.0.0", "yaml": "^1.10.0" + }, + "dependencies": { + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + } } }, "cron-parser": { @@ -20483,9 +20501,9 @@ "dev": true }, "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz", + "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==", "dev": true } } diff --git a/package.json b/package.json index 42fd8b36..8d7095b0 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,8 @@ "stylelint-config-recommended-scss": "^5.0.1", "stylelint-config-standard-scss": "^2.0.1", "svgo": "^2.8.0", - "typescript": "^4.3.5" + "typescript": "^4.3.5", + "yaml": "^2.2.1" }, "engine": { "peertube": ">=4.2.0" @@ -94,7 +95,8 @@ "build:serverconverse": "mkdir -p dist/server/conversejs && cp conversejs/index.html dist/server/conversejs/", "build:prosodymodules": "mkdir -p dist/server/prosody-modules && cp -r prosody-modules/* dist/server/prosody-modules/", "build:styles": "sass assets/styles:dist/assets/styles", - "build": "npm-run-all -s clean:light check:client:tsc -p build:converse build:prosody build:images build:avatars build:client build:server build:serverconverse build:prosodymodules build:styles", + "build:languages": "node ./build-languages.js", + "build": "npm-run-all -s clean:light check:client:tsc -p build:converse build:prosody build:images build:avatars build:client build:server build:languages build:serverconverse build:prosodymodules build:styles", "lint": "npm-run-all -s lint:script lint:styles", "lint:script": "npx eslint --ext .js --ext .ts .", "lint:styles": "stylelint 'conversejs/**/*.scss' 'assets/styles/**/*.css'", @@ -108,14 +110,14 @@ "settings": "dist/client/settings" }, "translations": { - "ca-ES": "./languages/ca.json", - "fr-FR": "./languages/fr.json", - "eo": "./languages/eo.json", - "eu-ES": "./languages/eu.json", - "oc": "./languages/oc.json", - "pl-PL": "./languages/pl.json", - "de-DE": "./languages/de.json", - "it-IT": "./languages/it.json", - "ja-JP": "./languages/ja.json" + "ca-ES": "./dist/languages/ca.json", + "fr-FR": "./dist/languages/fr.json", + "eo": "./dist/languages/eo.json", + "eu-ES": "./dist/languages/eu.json", + "oc": "./dist/languages/oc.json", + "pl-PL": "./dist/languages/pl.json", + "de-DE": "./dist/languages/de.json", + "it-IT": "./dist/languages/it.json", + "ja-JP": "./dist/languages/ja.json" } } diff --git a/server/lib/settings.ts b/server/lib/settings.ts index 72615a28..0620be40 100644 --- a/server/lib/settings.ts +++ b/server/lib/settings.ts @@ -1,30 +1,65 @@ import type { RegisterServerOptions } from '@peertube/peertube-types' import { ensureProsodyRunning } from './prosody/ctl' import type { ConverseJSTheme } from '../../shared/lib/types' +import { existsSync, promises as fsPromises } from 'fs' +import { resolve } from 'path' -function initSettings (options: RegisterServerOptions): void { +const locContent: Map = new Map() + +/** + * Currently, the Peertube plugin system assumes that settings strings + * are localized in english, and will be translated on front-end. + * This system make it hard to have complex strings (with html, newlines, ...). + * See https://github.com/Chocobozzz/PeerTube/issues/4523 + * + * Waiting for a better solution, we implemented a custom solution: + * - We are using keys to identify setting strings + * - the `loc` function gets the english segment for the key + * - the build-languages.js script builds all needed files. + * @param key The key to translate + */ +function loc (key: string): string { + return locContent.get(key) ?? key +} + +async function loadLoc (): Promise { + const filePath = resolve(__dirname, '..', '..', 'languages', 'settings.reference.json') + if (!existsSync(filePath)) { + throw new Error(`File ${filePath} missing, can't load plugin settings`) + } + const content = await fsPromises.readFile(filePath, 'utf8') + const json = JSON.parse(content ?? '{}') + if (typeof json !== 'object') { + throw new Error(`File ${filePath} invalid, can't load plugin settings`) + } + for (const k in json) { + const v = json[k] + if (typeof v === 'string') { + locContent.set(k, v) + } + } +} + +async function initSettings (options: RegisterServerOptions): Promise { const { peertubeHelpers, registerSetting, settingsManager } = options + await loadLoc() + // ********** IMPORTANT NOTES registerSetting({ type: 'html', private: true, - descriptionHTML: '

Important notes

' + descriptionHTML: loc('important_note_title') }) registerSetting({ type: 'html', private: true, - descriptionHTML: `You can find the plugin documentation here: - - Peertube Plugin Livechat documentation -.` + descriptionHTML: loc('important_note_text') }) registerSetting({ type: 'html', private: true, - descriptionHTML: `Before asking for help, please use the diagnostic tool: -Launch diagnostic -(if this button is not opening a new window, please try to refresh the page).` + descriptionHTML: loc('diagnostic') }) if (process.arch !== 'x64' && process.arch !== 'x86_64') { @@ -32,6 +67,8 @@ function initSettings (options: RegisterServerOptions): void { name: 'prosody-arch-warning', type: 'html', private: true, + // Note: the following text as a variable in it. + // Not translating it: it should be very rare. descriptionHTML: ` It seems that your are using a ${process.arch} CPU, which is not compatible with the plugin. @@ -50,13 +87,13 @@ Please read registerSetting({ type: 'html', private: true, - descriptionHTML: '

Chat

' + descriptionHTML: loc('chat_title') }) registerSetting({ name: 'prosody-list-rooms', - label: 'List existing rooms', + label: loc('list_rooms_label'), type: 'html', - descriptionHTML: 'List rooms', + descriptionHTML: loc('list_rooms_description'), private: true }) @@ -64,102 +101,94 @@ Please read registerSetting({ type: 'html', private: true, - descriptionHTML: '

Chat behaviour

' + descriptionHTML: loc('chat_behaviour_description') }) registerSetting({ name: 'prosody-room-type', - label: 'Room type', + label: loc('room_type_label'), type: 'select', - descriptionHTML: 'You can choose here to have separate rooms for each video, or to group them by channel.', + descriptionHTML: loc('room_type_description'), private: false, default: 'video', options: [ - { value: 'video', label: 'Each video has its own webchat room' }, - { value: 'channel', label: 'Webchat rooms are grouped by channel' } + { value: 'video', label: loc('room_type_option_video') }, + { value: 'channel', label: loc('room_type_option_channel') } ] }) registerSetting({ name: 'chat-auto-display', - label: 'Automatically open the chat', - descriptionHTML: 'When watching a video, the chatbox will automatically open', + label: loc('auto_display_label'), + descriptionHTML: loc('auto_display_description'), type: 'input-checkbox', default: true, private: false }) registerSetting({ name: 'chat-open-blank', - label: 'Show the «open in new window» button', - descriptionHTML: 'There will be a button for opening the web chat in a new window.', + label: loc('open_blank_label'), + descriptionHTML: loc('open_blank_description'), private: false, type: 'input-checkbox', default: true }) registerSetting({ name: 'chat-share-url', - label: 'Show the «share chat link» button', - descriptionHTML: 'There will be a button for sharing a chat url (could be used to intregrated in OBS for example).', + label: loc('share_url_label'), + descriptionHTML: loc('share_url_description'), private: false, type: 'select', default: 'owner', options: [ - { label: 'Show for nobody', value: 'nobody' }, - { label: 'Show for everyone', value: 'everyone' }, - { label: 'Show for the video owner', value: 'owner' }, - { label: 'Show for the video owner and instance\'s moderators', value: 'owner+moderators' } + { value: 'nobody', label: loc('share_url_option_nobody') }, + { value: 'everyone', label: loc('share_url_option_everyone') }, + { value: 'owner', label: loc('share_url_option_owner') }, + { value: 'owner+moderators', label: loc('share_url_option_owner_moderators') } ] }) registerSetting({ name: 'chat-per-live-video', - label: 'Users can activate the chat for their lives', + label: loc('per_live_video_label'), type: 'input-checkbox', default: true, - descriptionHTML: 'If checked, all live videos will have a checkbox in their properties for enabling the web chat.', + descriptionHTML: loc('per_live_video_description'), private: false }) registerSetting({ name: 'chat-per-live-video-warning', type: 'html', private: true, - descriptionHTML: -` - You have enabled the setting «Users can activate the chat for their lives». - It is redundant with the «Activate chat for all lives» setting. -` + descriptionHTML: loc('per_live_video_warning_description') }) registerSetting({ name: 'chat-all-lives', - label: 'Activate chat for all lives', + label: loc('all_lives_label'), type: 'input-checkbox', default: false, - descriptionHTML: 'If checked, the chat will be enabled for all lives.', + descriptionHTML: loc('all_lives_description'), private: false }) registerSetting({ name: 'chat-all-non-lives', - label: 'Activate chat for all non-lives', + label: loc('all_non_lives_label'), type: 'input-checkbox', default: false, - descriptionHTML: 'If checked, the chat will be enable for all video that are not lives.', + descriptionHTML: loc('all_non_lives_description'), private: false }) registerSetting({ name: 'chat-videos-list', - label: 'Activate chat for these videos', + label: loc('videos_list_label'), type: 'input-textarea', default: '', - descriptionHTML: -`Videos UUIDs for which we want a web chat. -Can be non-live videos. One per line.
-You can add comments: everything after the # character will be stripped off, and empty lines ignored.
-Don't add private videos, the UUIDs will be send to frontend.`, + descriptionHTML: loc('videos_list_description'), private: false }) registerSetting({ name: 'chat-no-anonymous', - label: 'Hide the chat for anonymous users', + label: loc('no_anonymous_label'), type: 'input-checkbox', default: false, - descriptionHTML: 'If checked, anonymous Peertube users won\'t see the chat.', + descriptionHTML: loc('no_anonymous_description'), private: false }) @@ -168,47 +197,38 @@ Don't add private videos, the UUIDs will be send to frontend.`, name: 'theming-advanced', type: 'html', private: true, - descriptionHTML: '

Theming

' + descriptionHTML: loc('theming_advanced_description') }) registerSetting({ name: 'converse-theme', - label: 'ConverseJS theme', + label: loc('converse_theme_label'), type: 'select', default: 'peertube' as ConverseJSTheme, private: false, options: [ - { value: 'peertube', label: 'Peertube theme' }, - { value: 'default', label: 'Default ConverseJS theme' }, - { value: 'concord', label: 'ConverseJS concord theme' } + { value: 'peertube', label: loc('peertube') }, + { value: 'default', label: loc('default') }, + { value: 'concord', label: loc('concord') } ] as Array<{value: ConverseJSTheme, label: string}>, - descriptionHTML: 'Please choose the converseJS theme you want to use.' + descriptionHTML: loc('converse_theme_description') }) registerSetting({ name: 'converse-autocolors', - label: 'Automatic color detection', + label: loc('autocolors_label'), type: 'input-checkbox', default: true, private: false, - descriptionHTML: -`Try to auto detect colors from user's current theme.
-When this settings is enabled, the plugin tries to auto-detect colors to apply to the chat theme.
-If this is not correctly working for some of your Peertube theme, you can disable this option. -You can report the bug on the official - - issue tracker -. Don't forget to specify which theme is not working.` + descriptionHTML: loc('autocolors_description') }) registerSetting({ name: 'chat-style', - label: 'Webchat iframe style attribute', + label: loc('chat_style_label'), type: 'input-textarea', default: '', - descriptionHTML: -`Additional styles to be added on the iframe style attribute.
-Example: height:400px;`, + descriptionHTML: loc('chat_style_description'), private: false }) @@ -217,26 +237,22 @@ Example: height:400px;`, name: 'prosody-advanced', type: 'html', private: true, - descriptionHTML: '

Chat server advanced settings

' + descriptionHTML: loc('prosody_advanced_description') }) registerSetting({ name: 'chat-help-builtin-prosody', type: 'html', - label: 'Prosody server', - descriptionHTML: `This plugin uses the Prosody XMPP server to handle chat rooms.
-This plugin comes with a Prosody AppImage, that will be used to run the service.`, + label: loc('help_builtin_prosody_label'), + descriptionHTML: loc('help_builtin_prosody_description'), private: true }) registerSetting({ name: 'use-system-prosody', type: 'input-checkbox', - label: 'Use system Prosody', - descriptionHTML: `Warning: don't check this settings if you are not sure of what you are doing.
-By checking this settings, your Peertube will use the Prosody server that comes with your system, -and not the embeded AppImage.
-Only use this if you encounter problems with the embedded Prosody.`, + label: loc('system_prosody_label'), + descriptionHTML: loc('system_prosody_description'), private: true, default: false }) @@ -244,142 +260,91 @@ Only use this if you encounter problems with the embedded Prosody.`, registerSetting({ name: 'disable-websocket', type: 'input-checkbox', - label: 'Disable Websocket', - descriptionHTML: `With Peertube >= 5.0.0, this plugin try to use Websocket connection for chatting. -If the user's browser or connection is not compatible, the browser will automatically fallback on the BOSH protocol. -
-But in rare case, this can fail. For example if you have a reverse proxy in front of Peertube that does not -allow Websocket connection for plugins. -In this case, you can check this settings to disable Websocket connections.`, + label: loc('disable_websocket_label'), + descriptionHTML: loc('disable_websocket_description'), private: true, default: false }) registerSetting({ name: 'prosody-port', - label: 'Prosody port', + label: loc('prosody_port_label'), type: 'input', default: '52800', private: true, - descriptionHTML: -`The port that will be used by the builtin Prosody server.
-Change it if this port is already in use on your server.
-You can close this port on your firewall, it will not be accessed from the outer world.` + descriptionHTML: loc('prosody_port_description') }) registerSetting({ name: 'prosody-peertube-uri', - label: 'Peertube url for API calls', + label: loc('prosody_peertube_uri_label'), type: 'input', default: '', private: true, - descriptionHTML: -`Please let this settings empty if you don't know what you are doing.
-In some rare case, Prosody can't call Peertube's API from its public URI. -You can use this field to customise Peertube's URI for Prosody modules -(for example with «http://localhost:9000» or «http://127.0.0.1:9000»).` + descriptionHTML: loc('prosody_peertube_uri_description') }) registerSetting({ name: 'prosody-muc-log-by-default', - label: 'Log rooms content by default', + label: loc('prosody_muc_log_by_default_label'), type: 'input-checkbox', default: true, private: true, - descriptionHTML: -`If checked, room contents will be saved by default. -Any user that join a room will see what was written before he joins.
-Please note that it is always possible to enable/disable the content -archiving for a specific room, by editing its properties. -` + descriptionHTML: loc('prosody_muc_log_by_default_description') }) registerSetting({ name: 'prosody-muc-expiration', - label: 'Room logs expiration', + label: loc('prosody_muc_expiration_label'), type: 'input', default: '1w', private: true, - descriptionHTML: -`You can choose here how long the chatting room's content is kept by the server. The value can be: -
    -
  • 60: the content will be saved for 60 seconds. You can replace 60 by any integer value.
  • -
  • 1d: the content will be saved for 1 day. You can replace 1 by any integer value.
  • -
  • 1w: the content will be saved for 1 week. You can replace 1 by any integer value.
  • -
  • 1m: the content will be saved for 1 month. You can replace 1 by any integer value.
  • -
  • 1y: the content will be saved for 1 year. You can replace 1 by any integer value.
  • -
  • never: the content will never expire, and will be kept forever.
  • -
` + descriptionHTML: loc('prosody_muc_expiration_description') }) registerSetting({ name: 'prosody-c2s', - label: 'Enable client to server connections', + label: loc('prosody_c2s_label'), type: 'input-checkbox', default: false, private: true, - descriptionHTML: -`Enable XMPP clients to connect to the builtin Prosody server.
-This option alone only allows connections from localhost clients.` + descriptionHTML: loc('prosody_c2s_description') }) registerSetting({ name: 'prosody-c2s-port', - label: 'Prosody client to server port', + label: loc('prosody_c2s_port_label'), type: 'input', default: '52822', private: true, - descriptionHTML: -`The port that will be used by the c2s module of the builtin Prosody server.
-XMPP clients shall use this port to connect.
-Change it if this port is already in use on your server.
-You can keep this port closed on your firewall for now, it will not be accessed from the outer world.` + descriptionHTML: loc('prosody_c2s_port_description') }) registerSetting({ name: 'prosody-components', - label: 'Enable custom Prosody external components', + label: loc('prosody_components_label'), type: 'input-checkbox', default: false, private: true, - descriptionHTML: -`Enable the use of external XMPP components.
-This option alone only allows connections from localhost.
-This feature can for example be used to connect some bots to the chatting rooms.` + descriptionHTML: loc('prosody_components_description') }) registerSetting({ name: 'prosody-components-port', - label: 'Prosody external components port', + label: loc('prosody_components_port_label'), type: 'input', default: '53470', private: true, - descriptionHTML: -`The port that will be used by XMPP components to connect to the Prosody server.
-Change it if this port is already in use on your server.
-You can keep this port closed on your firewall for now, it will not be accessed from the outer world.` + descriptionHTML: loc('prosody_components_port_description') }) registerSetting({ name: 'prosody-components-list', - label: 'External components', + label: loc('prosody_components_list_label'), type: 'input-textarea', default: '', private: true, - descriptionHTML: -`The external components to create: -
    -
  • One per line.
  • -
  • Use the format «component_name:component_secret» (spaces will be trimmed)
  • -
  • You can add comments: everything after the # character will be stripped off, and empty lines ignored
  • -
  • The name can only contain alphanumeric characters and dots
  • -
  • - If the name contains only alphanumeric characters, it will be suffixed with the XMPP domain. - For exemple «bridge» will become «bridge.your_domain.tld». - You can also specify a full domain name, but you have to make sure to configure your DNS correctly. -
  • -
  • Only use alphanumeric characters in the secret passphrase (use at least 15 characters).
  • -
` + descriptionHTML: loc('prosody_components_list_description') }) // ********** settings changes management diff --git a/support/documentation/content/contributing/translate/_index.en.md b/support/documentation/content/contributing/translate/_index.en.md index b45acb80..8b75acce 100644 --- a/support/documentation/content/contributing/translate/_index.en.md +++ b/support/documentation/content/contributing/translate/_index.en.md @@ -7,7 +7,15 @@ chapter=false You can help us to translate this PeerTube plugin by creating or modifying translation files in the `languages` folder. +{{% notice info %}} +For now, translation is done in the git repository. Later in 2023, online translation tools will be set (probably [Weblate](https://weblate.org)). This will make the translation process easier. +{{% /notice %}} + +{{% notice tip %}} Please work on the `develop` branch, and do your commits and pull request on this branch. +{{% /notice %}} + +## Standard application strings If the language you are interesting in does not exist yet, create a file `code.json` in the `languages` folder, where `code` is the language code. The language code must be the same as the Peertube's langage code (see [Peertube documentation](https://github.com/Chocobozzz/PeerTube/blob/develop/support/doc/translation.md)). @@ -19,3 +27,29 @@ Translation strings are set in the language file as follow: - the JSON key is the english string (see existing keys in the [french translation file](languages/fr.json)). - the JSON value is the translating string - NB: there is no english translation file (this is how translation works for peertube's plugins) + +## Settings translations + +In the plugin settings page, there are more complex strings. +They can be HTML code, with newlines, HTML tags, ... +This is not suitable for the JSON format. + +That's why the process is a little bit different for settings strings. + +Settings strings are defined in [YAML files](https://en.wikipedia.org/wiki/YAML). +They don't use the english text as key, but a codified key, like `list_rooms_label`. + +On the contrary of the standards application strings, there is also a configuration file for the english language. + +These files are in the folder `languages/settings`. If the file for the language that you are interested in does not exist, just create a new file +named `code.yml`, where `code` is the language code (see above). + +Then, you can copy YAML keys from the reference file `languages/settings/en.yml`, and translate strings. + +If you don't want to translate a string, you can ignore it, or use `null` or `~` as value. + +{{% notice warning %}} +There might be some «very technical» strings. If you are not 100% sure of +the meaning, or of your translation, you better not translate it, +so it will display in english. +{{% /notice %}} diff --git a/support/documentation/content/contributing/translate/_index.fr.md b/support/documentation/content/contributing/translate/_index.fr.md index dabc6776..afef1a4c 100644 --- a/support/documentation/content/contributing/translate/_index.fr.md +++ b/support/documentation/content/contributing/translate/_index.fr.md @@ -7,7 +7,18 @@ chapter=false Vous pouvez nous aider à traduire ce plugin Peertube en créant ou modifiant des fichiers de traduction dans le dossier `languages`. +{{% notice info %}} +Pour le moment, les traductions se font directement dans le dépôt git. +Plus tard en 2023, des outils de traduction en ligne seront mis en place +(probablement [Weblate](https://weblate.org)). +Le processus de traduction en sera plus simple. +{{% /notice %}} + +{{% notice tip %}} Merci de travailler sur la branche `develop`, et de faire vos _pull request_ sur cette branche. +{{% /notice %}} + +## Chaîne applicatives standard Si la langue dans laquelle vous souhaitez traduire n'existe pas encore, créez un fichier `code.json` dans le dossier `languages`, où `code` est le code langue. Le code langue doit être dans le même format que les codes langues de Peertube (voir la [documentation Peertube](https://github.com/Chocobozzz/PeerTube/blob/develop/support/doc/translation.md)). @@ -19,3 +30,36 @@ Les traductions sont sous la forme suivante dans le fichier de langue : - les clés JSON sont le texte en anglais (voir les clés existantes dans [le fichier de traduction français](languages/fr.json), qui fait référence) - la valeur JSON est la traduction - NB: il n'y a pas de fichier de traduction pour l'anglais (c'est la façon de fonctionner de Peertube) + +## Traduction des paramètres du plugin + +Dans la page des paramètres du plugin, il y a des chaînes de texte plus compliquées. +Elles peuvent contenir du code HTML, des retours à la ligne, ... +Il est donc compliqué de les maintenir dans des fichiers JSON. + +C'est pourquoi le processus de traduction est différent pour les traductions de paramètres. + +Les traductions des paramètres sont définies dans des fichiers [YAML](https://fr.wikipedia.org/wiki/YAML). +Elles n'utilisent pas l'anglais comme clé, mais des clés standardisées, +comme par exemple `list_rooms_label`. + +Au contraire des chaînes applicatives standard, il y a aussi un fichier de +configuration pour l'anglais. + +Ces fichiers sont dans le dossier `languages/settings`. +Si le fichier de la langue qui vous intéresse n'existe pas, vous +n'avez qu'à créer un fichier nommé `code.yml` où `code` est le code +de la langue (voir plus haut). + +Ensuite, vous pouvez copier les clés du fichier HTML de référence +`languages/settings/en.yml`, et traduire les chaînes de texte. + +Si vous ne voulez pas traduire une chaîne, vous pouvez l'ignorer, +ou utiliser `null` ou `~` comme valeur. + +{{% notice warning %}} +Il peut y avoir des chaînes «assez techniques». +Si vous n'êtes pas sûr⋅e à 100% du sens, ou de la traduction, +il vaut mieux ne pas la traduire du tout ; +ainsi la version anglaise s'affichera. +{{% /notice %}}