Doc: Allow translating documentation

pull/8077/head
Laurent Cozic 2023-04-23 22:33:15 +01:00
parent 738f1decbb
commit 40e1b0559e
16 changed files with 298 additions and 5099 deletions

View File

@ -874,6 +874,8 @@ packages/tools/website/updateDownloadPage.js
packages/tools/website/updateNews.js
packages/tools/website/utils/applyTranslations.js
packages/tools/website/utils/applyTranslations.test.js
packages/tools/website/utils/convertLinksToLocale.js
packages/tools/website/utils/convertLinksToLocale.test.js
packages/tools/website/utils/frontMatter.js
packages/tools/website/utils/news.js
packages/tools/website/utils/openGraph.js

2
.gitignore vendored
View File

@ -861,6 +861,8 @@ packages/tools/website/updateDownloadPage.js
packages/tools/website/updateNews.js
packages/tools/website/utils/applyTranslations.js
packages/tools/website/utils/applyTranslations.test.js
packages/tools/website/utils/convertLinksToLocale.js
packages/tools/website/utils/convertLinksToLocale.test.js
packages/tools/website/utils/frontMatter.js
packages/tools/website/utils/news.js
packages/tools/website/utils/openGraph.js

View File

@ -657,6 +657,16 @@ footer .bottom-links-row p {
font-size: 1.1em;
}
.language-switcher {
display: inline;
}
.language-switcher > button {
border: none;
background-color: transparent;
color: #0557ba;
}
/*****************************************************************
WHAT'S NEW PAGE
*****************************************************************/

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -421,7 +421,7 @@
</div>
<script
src="{{jsBaseUrl}}/bootstrap5.0.2.min.js"
src="{{jsBaseUrl}}/bootstrap5.0.2.bundle.min.js"
rel="preload"
as="script"
></script>

View File

@ -85,6 +85,11 @@ https://github.com/laurent22/joplin/blob/dev/{{{sourceMarkdownFile}}}
{{> footer}}
</div>
<script
src="{{jsBaseUrl}}/bootstrap5.0.2.bundle.min.js"
rel="preload"
as="script"
></script>
<script src="{{{assetUrls.js.script}}}"></script>
{{> analytics}}

View File

@ -17,6 +17,21 @@
<a href="{{baseUrl}}/help/" class="fw500">Help</a>
<a href="{{forumUrl}}" class="fw500">Forum</a>
<a href="{{baseUrl}}/cn/" class="fw500">中文</a>
<!--
<div class="dropdown language-switcher">
<button class="fw500" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">
Language
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
</ul>
</div>
-->
{{#showJoplinCloudLinks}}
{{> joplinCloudButton}}
{{/showJoplinCloudLinks}}

7
bootstrap.bundle.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,19 +1,20 @@
import { readFileSync, readFile, mkdirpSync, writeFileSync, remove, copy, pathExistsSync } from 'fs-extra';
import { readFileSync, readFile, mkdirpSync, writeFileSync, remove, copy, pathExistsSync, pathExists } from 'fs-extra';
import { rootDir } from '../tool-utils';
import { pressCarouselItems } from './utils/pressCarousel';
import { getMarkdownIt, loadMustachePartials, markdownToPageHtml, renderMustache } from './utils/render';
import { AssetUrls, Env, Partials, PlanPageParams, TemplateParams } from './utils/types';
import { AssetUrls, Env, Locale, Partials, PlanPageParams, TemplateParams } from './utils/types';
import { createFeatureTableMd, getPlans, loadStripeConfig } from '@joplin/lib/utils/joplinCloud';
import { stripOffFrontMatter } from './utils/frontMatter';
import { dirname, basename } from 'path';
import { readmeFileTitle, replaceGitHubByWebsiteLinks } from './utils/parser';
import { extractOpenGraphTags } from './utils/openGraph';
import { extractOpenGraphTags, OpenGraphTags } from './utils/openGraph';
import { readCredentialFileJson } from '@joplin/lib/utils/credentialFiles';
import { getNewsDateString } from './utils/news';
import { parsePoFile, parseTranslations, Translations } from '../utils/translation';
import { countryCodeOnly, setLocale } from '@joplin/lib/locale';
import { setLocale } from '@joplin/lib/locale';
import applyTranslations from './utils/applyTranslations';
import { loadSponsors } from '../utils/loadSponsors';
import convertLinksToLocale from './utils/convertLinksToLocale';
interface BuildConfig {
env: Env;
@ -23,6 +24,12 @@ const buildConfig = readCredentialFileJson<BuildConfig>('website-build.json', {
env: Env.Prod,
});
const enGbLocale: Locale = {
htmlTranslations: {},
lang: 'en-gb',
pathPrefix: '',
};
const glob = require('glob');
const path = require('path');
const md5File = require('md5-file');
@ -41,7 +48,7 @@ const partialDir = `${websiteAssetDir}/templates/partials`;
const discussLink = 'https://discourse.joplinapp.org/c/news/9';
let tocMd_: string = null;
let tocHtml_: string = null;
const tocHtml_: Record<string, string> = {};
const tocRegex_ = /<!-- TOC -->([^]*)<!-- TOC -->/;
function tocMd() {
if (tocMd_) return tocMd_;
@ -61,15 +68,17 @@ async function getDonateLinks() {
return `<div class="donate-links">\n\n${matches[1].trim()}\n\n</div>`;
}
function tocHtml() {
if (tocHtml_) return tocHtml_;
function tocHtml(locale: Locale) {
if (tocHtml_[locale.lang]) return tocHtml_[locale.lang];
const markdownIt = getMarkdownIt();
let md = tocMd();
md = md.replace(/# Table of contents/, '');
md = replaceGitHubByWebsiteLinks(md);
tocHtml_ = markdownIt.render(md);
tocHtml_ = `<div>${tocHtml_}</div>`;
return tocHtml_;
md = convertLinksToLocale(md, locale);
let output = markdownIt.render(md);
output = `<div>${output}</div>`;
tocHtml_[locale.lang] = output;
return output;
}
const baseUrl = '';
@ -90,14 +99,16 @@ async function getAssetUrls(): Promise<AssetUrls> {
};
}
function defaultTemplateParams(assetUrls: AssetUrls): TemplateParams {
function defaultTemplateParams(assetUrls: AssetUrls, locale: Locale = null): TemplateParams {
if (!locale) locale = enGbLocale;
return {
env: buildConfig.env,
baseUrl,
imageBaseUrl: `${baseUrl}/images`,
cssBaseUrl,
jsBaseUrl,
tocHtml: tocHtml(),
tocHtml: tocHtml(locale),
yyyy: (new Date()).getFullYear().toString(),
templateHtml: mainTemplateHtml,
forumUrl: 'https://discourse.joplinapp.org/',
@ -109,6 +120,7 @@ function defaultTemplateParams(assetUrls: AssetUrls): TemplateParams {
},
assetUrls,
openGraph: null,
locale,
};
}
@ -117,7 +129,7 @@ function renderPageToHtml(md: string, targetPath: string, templateParams: Templa
md = md.replace(/# Joplin\n/, '');
templateParams = {
...defaultTemplateParams(templateParams.assetUrls),
...defaultTemplateParams(templateParams.assetUrls, templateParams.locale),
...templateParams,
};
@ -133,6 +145,7 @@ function renderPageToHtml(md: string, targetPath: string, templateParams: Templa
}
md = replaceGitHubByWebsiteLinks(md);
md = convertLinksToLocale(md, templateParams.locale);
if (templateParams.donateLinksMd) {
md = `${templateParams.donateLinksMd}\n\n${md}`;
@ -161,8 +174,8 @@ function renderFileToHtml(sourcePath: string, targetPath: string, templateParams
}
}
function makeHomePageMd() {
let md = readFileSync(`${rootDir}/README.md`, 'utf8');
function makeHomePageMd(readmePath: string) {
let md = readFileSync(readmePath, 'utf8');
md = md.replace(tocRegex_, '');
// HACK: GitHub needs the \| or the inline code won't be displayed correctly inside the table,
@ -216,15 +229,20 @@ const updatePageLanguage = (html: string, lang: string): string => {
return html.replace('<html lang="en-gb">', `<html lang="${lang}">`);
};
// TODO: Add function that process links and add prefix.
async function main() {
const supportedLocales = {
'en_GB': {
htmlTranslations: {},
lang: 'en-gb',
},
const supportedLocales: Record<string, Locale> = {
'en_GB': enGbLocale,
'zh_CN': {
htmlTranslations: parseTranslations(await parsePoFile(`${websiteAssetDir}/locales/zh_CN.po`)),
lang: 'zh-cn',
pathPrefix: 'cn',
},
'fr_FR': {
htmlTranslations: {},
lang: 'fr-fr',
pathPrefix: 'fr',
},
};
@ -237,15 +255,38 @@ async function main() {
const partials = await loadMustachePartials(partialDir);
const assetUrls = await getAssetUrls();
const readmeMd = makeHomePageMd();
const donateLinksMd = await getDonateLinks();
for (const [localeName, locale] of Object.entries(supportedLocales)) {
setLocale(localeName);
const pathPrefix = localeName !== 'en_GB' ? `/${locale.pathPrefix}` : '';
// =============================================================
// HELP PAGE
// =============================================================
renderPageToHtml(readmeMd, `${docDir}/help/index.html`, {
sourceMarkdownFile: 'README.md',
let readmePath = `${rootDir}/README.md`;
let sourceMarkdownFile = 'README.md';
let targetDocDir = docDir;
if (localeName !== 'en_GB') {
const possibleSource = `${rootDir}/readme/_i18n/${localeName}/README.md`;
if (await pathExists(possibleSource)) {
sourceMarkdownFile = possibleSource;
readmePath = possibleSource;
} else {
console.warn(`Cannot find source file: ${possibleSource}`);
}
targetDocDir = `${docDir}/${locale.pathPrefix}`;
}
const readmeMd = makeHomePageMd(readmePath);
renderPageToHtml(readmeMd, `${targetDocDir}/help/index.html`, {
sourceMarkdownFile,
donateLinksMd,
partials,
sponsors,
@ -255,17 +296,13 @@ async function main() {
description: '',
url: 'https://joplinapp.org/help/',
},
locale,
});
// =============================================================
// FRONT PAGE
// =============================================================
for (const [localeName, locale] of Object.entries(supportedLocales)) {
setLocale(localeName);
const pathPrefix = localeName !== 'en_GB' ? `/${countryCodeOnly(localeName).toLowerCase()}` : '';
let templateHtml = updatePageLanguage(applyTranslations(frontTemplateHtml, localeName, locale.htmlTranslations), locale.lang);
if (localeName === 'zh_CN') templateHtml = templateHtml.replace(/\/plans/g, '/cn/plans');
@ -292,22 +329,16 @@ async function main() {
url: 'https://joplinapp.org',
},
});
}
setLocale('en_GB');
// =============================================================
// PLANS PAGE
// =============================================================
for (const [localeName, locale] of Object.entries(supportedLocales)) {
setLocale(localeName);
const planPageFaqMd = await readFile(`${readmeDir}/faq_joplin_cloud.md`, 'utf8');
const planPageFaqHtml = getMarkdownIt().render(planPageFaqMd, {});
const planPageParams: PlanPageParams = {
...defaultTemplateParams(assetUrls),
...defaultTemplateParams(assetUrls, locale),
partials: translatePartials(partials, localeName, locale.htmlTranslations),
templateHtml: applyTranslations(plansTemplateHtml, localeName, locale.htmlTranslations),
plans: getPlans(stripeConfig),
@ -318,10 +349,8 @@ async function main() {
const planPageContentHtml = renderMustache('', planPageParams);
const pathPrefix = localeName !== 'en_GB' ? `/${countryCodeOnly(localeName).toLowerCase()}` : '';
const templateParams = {
...defaultTemplateParams(assetUrls),
...defaultTemplateParams(assetUrls, locale),
pageName: 'plans',
partials,
showToc: false,
@ -342,10 +371,20 @@ async function main() {
// Markdown files under /readme
// =============================================================
const mdFiles = glob.sync(`${readmeDir}/**/*.md`).map((f: string) => f.substr(rootDir.length + 1));
const sources = [];
interface SourceInfo {
title: string;
donateLinksMd: string;
showToc: boolean;
openGraph: OpenGraphTags;
sourceMarkdownName?: string;
sourceMarkdownFile?: string;
locale: Locale;
}
const makeTargetBasename = (input: string): string => {
const mdFiles: string[] = glob.sync(`${readmeDir}/**/*.md`).map((f: string) => f.substr(rootDir.length + 1));
const sources: [string, string, SourceInfo][] = [];
const makeTargetBasename = (input: string, pathPrefix: string): string => {
if (isNewsFile(input)) {
const filenameNoExt = basename(input, '.md');
return `news/${filenameNoExt}/index.html`;
@ -364,35 +403,50 @@ async function main() {
s = s.replace(/readme\//, '');
if (pathPrefix) s = `${pathPrefix}/${s}`;
return s;
}
};
const makeTargetFilePath = (input: string): string => {
return `${docDir}/${makeTargetBasename(input)}`;
const makeTargetFilePath = (input: string, pathPrefix: string): string => {
return `${docDir}/${makeTargetBasename(input, pathPrefix)}`;
};
const makeTargetUrl = (input: string) => {
return `https://joplinapp.org/${makeTargetBasename(input)}`;
const makeTargetUrl = (input: string, pathPrefix: string) => {
return `https://joplinapp.org/${makeTargetBasename(input, pathPrefix)}`;
};
const newsFilePaths: string[] = [];
for (const mdFile of mdFiles) {
if (mdFile.startsWith('readme/_i18n')) continue;
for (const [localeName, locale] of Object.entries(supportedLocales)) {
const title = await readmeFileTitle(`${rootDir}/${mdFile}`);
const targetFilePath = makeTargetFilePath(mdFile);
const openGraph = await extractOpenGraphTags(mdFile, makeTargetUrl(mdFile));
const targetFilePath = makeTargetFilePath(mdFile, locale.pathPrefix);
const openGraph = await extractOpenGraphTags(mdFile, makeTargetUrl(mdFile, locale.pathPrefix));
const isNews = isNewsFile(mdFile);
if (isNews) newsFilePaths.push(mdFile);
sources.push([mdFile, targetFilePath, {
let sourceFile = mdFile;
if (localeName !== 'en_GB') {
let temp = mdFile.replace(/readme\//, '');
temp = `readme/_i18n/${localeName}/${temp}`;
if (await pathExists(temp)) sourceFile = temp;
}
sources.push([sourceFile, targetFilePath, {
title: title,
donateLinksMd: mdFile === 'readme/donate.md' ? '' : donateLinksMd,
showToc: mdFile !== 'readme/download.md' && !isNews,
openGraph,
locale,
}]);
}
}
for (const source of sources) {
source[2].sourceMarkdownFile = source[0];
@ -418,7 +472,7 @@ async function main() {
});
await makeNewsFrontPage(newsFilePaths, `${docDir}/news/index.html`, {
...defaultTemplateParams(assetUrls),
...defaultTemplateParams(assetUrls, null),
title: 'What\'s new',
pageName: 'news',
partials,

View File

@ -0,0 +1,25 @@
import convertLinksToLocale from './convertLinksToLocale';
describe('convertLinksToLocale', () => {
it('should convert links', async () => {
const tests: [string, any, string][] = [
[
'test [link](/help/link)',
{ pathPrefix: 'fr' },
'test [link](/fr/help/link)',
],
[
'test [link](/help/link) [link2](/link2)',
{ pathPrefix: 'fr' },
'test [link](/fr/help/link) [link2](/fr/link2)',
],
];
for (const [input, locale, expected] of tests) {
const actual = convertLinksToLocale(input, locale);
expect(actual).toBe(expected);
}
});
});

View File

@ -0,0 +1,9 @@
import { Locale } from './types';
export default (md: string, locale: Locale) => {
if (locale.lang === 'en-gb') return md;
md = md.replace(/\(\//g, `(/${locale.pathPrefix}/`);
return md;
};

View File

@ -7,6 +7,12 @@ export enum Env {
Prod = 'prod',
}
export interface Locale {
htmlTranslations: Record<string, string>;
lang: string;
pathPrefix: string;
}
export interface GithubUser {
id: string;
}
@ -62,6 +68,7 @@ export interface TemplateParams {
showBottomLinks?: boolean;
openGraph: OpenGraphTags;
isNews?: boolean;
locale?: Locale;
}
export interface PlanPageParams extends TemplateParams {

View File

@ -0,0 +1,74 @@
<!-- DONATELINKS -->
[! [Faire un don via PayPal] (https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=E8JMYD2LQ8MMA&lc=GB&item_name=Joplin+Development¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted) [! [Sponsor sur GitHub] (https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/GitHub-Badge.svg)](https://github.com/sponsors/laurent22/) [! [Devenez mécène] (https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/Patreon-Badge.svg)](https://www.patreon.com/joplin) [! [Faire un don en utilisant un IBAN] (https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/Donate-IBAN.svg)](https://joplinapp.org/donate/#donations)
<!-- DONATELINKS -->
* * *
**TEST ONLY**
* * *
[test link](/spec/e2ee)
<img width="64" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/LinuxIcons/256x256.png" align="left" />**Joplin** est une application gratuite et open source de prise de notes et de tâches, qui peut gérer un grand nombre de notes organisées dans des carnets de notes. Les notes sont consultables, peuvent être copiées, balisées et modifiées directement depuis les applications ou depuis votre propre éditeur de texte. Les notes sont au format [Markdown] (#markdown).
Les notes exportées depuis Evernote [peuvent être importées] (#importing) dans Joplin, y compris le contenu formaté (qui est converti en Markdown), les ressources (images, pièces jointes, etc.) et les métadonnées complètes (géolocalisation, heure de mise à jour, heure de création, etc.). Les fichiers Markdown simples peuvent également être importés.
Les notes peuvent être [synchronisées] (#synchronisation) en toute sécurité à l'aide du [chiffrement de bout en bout] (#encryption) avec divers services cloud, notamment Nextcloud, Dropbox, OneDrive et [Joplin Cloud] (https://joplinapp.org/plans/).
La recherche en texte intégral est disponible sur toutes les plateformes pour trouver rapidement les informations dont vous avez besoin. L'application peut être personnalisée à l'aide de plugins et de thèmes, et vous pouvez également créer facilement le vôtre.
L'application est disponible pour Windows, Linux, macOS, Android et iOS. Un [Web Clipper] (https://github.com/laurent22/joplin/blob/dev/readme/clipper.md), qui permet d'enregistrer des pages Web et des captures d'écran depuis votre navigateur, est également disponible pour [Firefox] (https://addons.mozilla.org/firefox/addon/joplin-web-clipper/) et [Chrome] (https://chrome.google.com/webstore/detail/joplin-web-clipper/alofnhikmmkdbbbgpnglcpdollgjjfek?hl=en-GB).
<div class="top-screenshot"></div><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/home-top-img.png" style="max-width: 100%; max-height: 35em;">
# Installation
Trois types d'applications sont disponibles : pour **bureau** (Windows, macOS et Linux), pour **mobile** (Android et iOS) et pour **terminal** (Windows, macOS, Linux et FreeBSD). Toutes les applications disposent d'interfaces utilisateur similaires et peuvent se synchroniser entre elles.
## Applications de bureau
Système d'exploitation | Télécharger
---|---
Windows (32 et 64 bits) | <a href='https://github.com/laurent22/joplin/releases/download/v2.9.17/Joplin-Setup-2.9.17.exe'><img alt='Get it on Windows' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeWindows.png'/></a>
MacOS | <a href='https://github.com/laurent22/joplin/releases/download/v2.9.17/Joplin-2.9.17.dmg'><img alt='Get it on macOS' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeMacOS.png'/></a>
Linux | <a href='https://github.com/laurent22/joplin/releases/download/v2.9.17/Joplin-2.9.17.AppImage'><img alt='Get it on Linux' width="134px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeLinux.png'/></a>
<a href='https://github.com/laurent22/joplin/releases/download/v2.9.17/JoplinPortable.exe'>**Sous Windows**, vous pouvez également utiliser la version portable.</a> L' [application portable] (https://en.wikipedia.org/wiki/Portable_application) permet d'installer le logiciel sur un appareil portable tel qu'une clé USB. Copiez simplement le fichier JoplinPortable.exe dans n'importe quel répertoire de cette clé USB ; l'application créera alors un répertoire appelé « JoplinProfile » à côté du fichier exécutable.
**Sous Linux**, la méthode recommandée est d'utiliser le script d'installation suivant car il gérera également l'icône du bureau :
<pre><code style="word-break: break-all">wget -O - https://raw.githubusercontent.com/laurent22/joplin/dev/Joplin_install_and_update.sh | bash</code></pre>
## Applications mobiles
Système d'exploitation | Télécharger | Alt. Télécharger
---|---|---
Android | <a href='https://play.google.com/store/apps/details?id=net.cozic.joplin&utm_source=GitHub&utm_campaign=README&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeAndroid.png'/></a>| ou téléchargez le fichier APK : [64 bits] (https://github.com/laurent22/joplin-android/releases/download/android-v2.9.8/joplin-v2.9.8.apk) [32 bits] ( https://github.com/laurent22/joplin-android/releases/download/android-v2.9.8/joplin-v2.9.8-32bit.apk)
iOS | <a href='https://itunes.apple.com/us/app/joplin/id1315599797'><img alt='Get it on the App Store' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/BadgeIOS.png'/></a>| -
## Application du terminal
Système d'exploitation | Méthode
-----------------|----------------
macOS, Linux ou Windows (via [WSL] (https://msdn.microsoft.com/en-us/commandline/wsl/faq?f=255&MSPPError=-2147217396)) | **Important :** Tout d'abord, [installez Node 12+] (https://nodejs.org/en/download/package-manager/). <br/><br/><br><br>`NPM_CONFIG_PREFIX=~/.joplin-bin npm install -g joplin` `sudo ln -s ~/.joplin-bin/bin/joplin /usr/bin/joplin `Par défaut, le binaire de l'application sera installé sous <br/> `~/.joplin-bin`. Vous pouvez modifier ce répertoire si nécessaire. Sinon, si vos autorisations npm sont configurées comme décrit [ici] (https://docs.npmjs.com/getting-started/fixing-npm-permissions#option-2-change-npms-default-directory-to-another-directory) (Option 2), il suffit d'exécuter `npm -g install joplin`.
Pour le démarrer, tapez `joplin`.
Pour des informations d'utilisation, veuillez consulter la [Documentation complète de l'application Joplin Terminal] (https://joplinapp.org/terminal/).
## Web Clipper
Le Web Clipper est une extension de navigateur qui vous permet d'enregistrer des pages Web et des captures d'écran à partir de votre navigateur. Pour plus d'informations sur son installation et son utilisation, consultez la [Page d'aide de Web Clipper] (https://github.com/laurent22/joplin/blob/dev/readme/clipper.md).
## Distributions alternatives non officielles
Il existe un certain nombre de distributions alternatives non officielles de Joplin. Si vous ne voulez pas ou ne pouvez pas utiliser appimages ou l'une des autres versions officiellement prises en charge, vous pouvez envisager de les utiliser.
Cependant, ils sont assortis d'une mise en garde dans la mesure où ils ne sont pas officiellement pris en charge, de sorte que certains problèmes peuvent ne pas être pris en charge par le projet principal. Les demandes d'assistance, les rapports de bogues et les conseils généraux devraient plutôt être adressés aux responsables de ces distributions.
Une liste de ces distributions gérée par la communauté est disponible ici : [Distributions Joplin non officielles] (https://discourse.joplinapp.org/t/unofficial-alternative-joplin-distributions/23703)
# Sponsors
<!-- SPONSORS-ORG -->
</a><a href="https://seirei.ne.jp"><img title="Serei Network" width="256" src="https://joplinapp.org/images/sponsors/SeireiNetwork.png"/><a href="https://www.hosting.de/nextcloud/?mtm_campaign=managed-nextcloud&mtm_kwd=joplinapp&mtm_source=joplinapp-webseite&mtm_medium=banner"><img title="Hosting.de" width="256" src="https://joplinapp.org/images/sponsors/HostingDe.png"/></a><a href="https://residence-greece.com/"><img title="Greece Golden Visa" width="256" src="https://joplinapp.org/images/sponsors/ResidenceGreece.jpg"/></a> <a href="https://grundstueckspreise.info/"><img title="SP Software GmbH" width="256" src="https://joplinapp.org/images/sponsors/Grundstueckspreise.png"/></a>
<!-- SPONSORS-ORG -->

View File

@ -0,0 +1,5 @@
# Application de bureau
<img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/DemoDesktop.png" style="width: 100%">
Pour des informations générales relatives à toutes les applications, voir aussi [la page de garde](https://joplinapp.org).