Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=for-the-badge)](https://opensource.org/licenses/MIT)
[![Build Status](https://github.com/GSiesto/pdflince/actions/workflows/deploy.yml/badge.svg?style=for-the-badge)](https://github.com/GSiesto/pdflince/actions)

| 🇬🇧 English | 🇪🇸 Español | 🇩🇪 Deutsch | 🇵🇹 Português | 🇮🇹 Italiano |
|:---:|:---:|:---:|:---:|:---:|
| [pdflince.com](https://pdflince.com/en?utm_source=github&utm_medium=readme&utm_campaign=pdflince_public) | [pdflince.com](https://pdflince.com/?utm_source=github&utm_medium=readme&utm_campaign=pdflince_public) | [pdflince.com](https://pdflince.com/de?utm_source=github&utm_medium=readme&utm_campaign=pdflince_public) | [pdflince.com](https://pdflince.com/pt?utm_source=github&utm_medium=readme&utm_campaign=pdflince_public) | [pdflince.com](https://pdflince.com/it?utm_source=github&utm_medium=readme&utm_campaign=pdflince_public)
| English | Español | Français | Deutsch | Português | Italiano |
|:---:|:---:|:---:|:---:|:---:|:---:|
| [pdflince.com](https://pdflince.com/en?utm_source=github&utm_medium=readme&utm_campaign=pdflince_public) | [pdflince.com](https://pdflince.com/?utm_source=github&utm_medium=readme&utm_campaign=pdflince_public) | [pdflince.com](https://pdflince.com/fr?utm_source=github&utm_medium=readme&utm_campaign=pdflince_public) | [pdflince.com](https://pdflince.com/de?utm_source=github&utm_medium=readme&utm_campaign=pdflince_public) | [pdflince.com](https://pdflince.com/pt?utm_source=github&utm_medium=readme&utm_campaign=pdflince_public) | [pdflince.com](https://pdflince.com/it?utm_source=github&utm_medium=readme&utm_campaign=pdflince_public)

## 🚀 Why PDFLince?
## Why PDFLince?

Most online PDF tools require you to upload your sensitive documents to their cloud servers for processing. This creates privacy risks and compliance issues.

Expand All @@ -22,7 +22,7 @@ Most online PDF tools require you to upload your sensitive documents to their cl
- **Offline Capable**: Works even without an internet connection once loaded.
- **No File Size Limits**: Bypasses server payload limits since it uses your device's memory.

## Features
## Features

- **Compress**: Smart compression with adaptive image downscaling (WebWorker-powered).
- **Merge**: Combine multiple PDFs into one document.
Expand All @@ -32,9 +32,9 @@ Most online PDF tools require you to upload your sensitive documents to their cl
- **Crop**: Crop PDF pages manually with visual selection or by specifying precise values
- **Rotate**: Rotate selected pages and preview changes in real-time before exporting.
- **Secure**: 100% local processing verifiable via Network tab.
- **Multilingual**: Native support for English, Spanish, German, Portuguese, Italian.
- **Multilingual**: Native support for English, Spanish, French, German, Portuguese, Italian.

## 🛠️ Architecture
## Architecture

Built with a focus on performance and code quality. The key differentiator is the **Zero-Server Data Flow**:

Expand Down Expand Up @@ -71,7 +71,7 @@ graph TD
- **Styling**: Tailwind CSS with a custom design system.
- **Testing**: Playwright End-to-End test suite ensuring reliability across all operations.

## ⚙️ Local Development
## Local Development

### Prerequisites
- Node.js 18+
Expand All @@ -98,17 +98,17 @@ graph TD
4. **Open in browser:**
Navigate to [http://localhost:3000](http://localhost:3000).

## 🤝 Contributing
## Contributing

Contributions are welcome! Whether it's fixing bugs, improving documentation, or proposing new features.

Please read our [Contributing Guidelines](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md) before getting started.

## 📄 License
## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## 💡 About the Name
## About the Name

"Lince" means **Lynx** in Spanish. The **Iberian Lynx** (*Lynx pardinus*) is a wild cat species native to the Iberian Peninsula (Spain/Portugal). It was once the most endangered feline species in the world, but conservation efforts are helping its population recover.

Expand Down
36 changes: 24 additions & 12 deletions content/i18n-route-map.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,85 +4,97 @@
"en": "/en",
"pt": "/pt",
"de": "/de",
"it": "/it"
"it": "/it",
"fr": "/fr"
},
"faq": {
"es": "/preguntas-frecuentes",
"en": "/en/faq",
"pt": "/pt/perguntas-frequentes",
"de": "/de/haeufige-fragen",
"it": "/it/faq"
"it": "/it/faq",
"fr": "/fr/faq"
},
"support": {
"es": "/apoya",
"en": "/en/support",
"pt": "/pt/apoie",
"de": "/de/unterstuetzen",
"it": "/it/supporto"
"it": "/it/supporto",
"fr": "/fr/soutenir"
},
"operations": {
"compress": {
"es": "/comprimir",
"en": "/en/compress",
"pt": "/pt/comprimir",
"de": "/de/komprimieren",
"it": "/it/comprimi"
"it": "/it/comprimi",
"fr": "/fr/compresser"
},
"merge": {
"es": "/unir",
"en": "/en/merge",
"pt": "/pt/juntar",
"de": "/de/zusammenfuehren",
"it": "/it/unisci"
"it": "/it/unisci",
"fr": "/fr/fusionner"
},
"split": {
"es": "/dividir",
"en": "/en/split",
"pt": "/pt/dividir",
"de": "/de/teilen",
"it": "/it/dividi"
"it": "/it/dividi",
"fr": "/fr/diviser"
},
"extract": {
"es": "/extraer",
"en": "/en/extract",
"pt": "/pt/extrair",
"de": "/de/seiten-extrahieren",
"it": "/it/estrai"
"it": "/it/estrai",
"fr": "/fr/extraire"
},
"crop": {
"es": "/recortar",
"en": "/en/crop",
"pt": "/pt/recortar",
"de": "/de/zuschneiden",
"it": "/it/ritaglia"
"it": "/it/ritaglia",
"fr": "/fr/recadrer"
},
"rotate": {
"es": "/girar",
"en": "/en/rotate",
"pt": "/pt/girar",
"de": "/de/drehen",
"it": "/it/ruota"
"it": "/it/ruota",
"fr": "/fr/faire-pivoter"
},
"reorder": {
"es": "/reordenar",
"en": "/en/reorder",
"pt": "/pt/reordenar",
"de": "/de/seiten-sortieren",
"it": "/it/riordina"
"it": "/it/riordina",
"fr": "/fr/reorganiser"
},
"pdfToImages": {
"es": "/convertir-pdf-a-imagenes",
"en": "/en/pdf-to-images",
"pt": "/pt/pdf-para-imagens",
"de": "/de/pdf-zu-bildern",
"it": "/it/da-pdf-a-immagini"
"it": "/it/da-pdf-a-immagini",
"fr": "/fr/pdf-en-images"
},
"imagesToPdf": {
"es": "/crear-pdf-desde-imagenes",
"en": "/en/images-to-pdf",
"pt": "/pt/imagens-para-pdf",
"de": "/de/bilder-zu-pdf",
"it": "/it/da-immagini-a-pdf"
"it": "/it/da-immagini-a-pdf",
"fr": "/fr/creer-pdf-depuis-images"
}
}
}
3 changes: 2 additions & 1 deletion public/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ PDFLince se creó para la comunidad hispanohablante, siendo ahora multilingüe,

## Idiomas Disponibles / Available Languages

PDFLince está disponible en 5 idiomas. Puedes acceder a la versión que prefieras:
PDFLince está disponible en 6 idiomas. Puedes acceder a la versión que prefieras:

- [Español (Principal)](https://pdflince.com)
- [English](https://pdflince.com/en)
- [Français](https://pdflince.com/fr)
- [Deutsch](https://pdflince.com/de)
- [Português](https://pdflince.com/pt)
- [Italiano](https://pdflince.com/it)
Expand Down
2 changes: 2 additions & 0 deletions src/app/(es)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export const metadata = {
'es': 'https://pdflince.com',
'en': 'https://pdflince.com/en',
'en-US': 'https://pdflince.com/en',
'fr': 'https://pdflince.com/fr',
'fr-FR': 'https://pdflince.com/fr',
'pt': 'https://pdflince.com/pt',
'pt-BR': 'https://pdflince.com/pt',
'de': 'https://pdflince.com/de',
Expand Down
2 changes: 2 additions & 0 deletions src/app/de/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export const metadata = {
'es': 'https://pdflince.com',
'en': 'https://pdflince.com/en',
'en-US': 'https://pdflince.com/en',
'fr': 'https://pdflince.com/fr',
'fr-FR': 'https://pdflince.com/fr',
'pt': 'https://pdflince.com/pt',
'pt-BR': 'https://pdflince.com/pt',
'de': 'https://pdflince.com/de',
Expand Down
2 changes: 2 additions & 0 deletions src/app/en/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export const metadata = {
'es': 'https://pdflince.com',
'en': 'https://pdflince.com/en',
'en-US': 'https://pdflince.com/en',
'fr': 'https://pdflince.com/fr',
'fr-FR': 'https://pdflince.com/fr',
'pt': 'https://pdflince.com/pt',
'pt-BR': 'https://pdflince.com/pt',
'de': 'https://pdflince.com/de',
Expand Down
8 changes: 8 additions & 0 deletions src/app/fr/(operations)/[operation]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { createLocaleOperationHandlers } from "../../../(helpers)/operation-handlers";

const LOCALE = "fr" as const;

const { generateStaticParams, generateMetadata, OperationPage } = createLocaleOperationHandlers(LOCALE);

export { generateStaticParams, generateMetadata };
export default OperationPage;
12 changes: 12 additions & 0 deletions src/app/fr/faq/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { FaqPageContent } from "../../../components/FaqPageContent";
import { getDictionary } from "../../../i18n/get-dictionary";
import { createFaqMetadata } from "../../(helpers)/locale-metadata";

const LOCALE = "fr" as const;

export const generateMetadata = createFaqMetadata(LOCALE);

export default function FrFaqPage() {
const dictionary = getDictionary(LOCALE);
return <FaqPageContent dictionary={dictionary} />;
}
77 changes: 77 additions & 0 deletions src/app/fr/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import "../../styles/globals.css";
import { Suspense, type ReactNode } from "react";
import { GeistSans } from "geist/font/sans";
import { GeistMono } from "geist/font/mono";
import NavMenu from "../../components/NavMenu";
import Footer from "../../components/Footer";
import FotoLinceBanner from "../../components/FotoLinceBanner";
import { LocaleProvider } from "../../i18n/LocaleProvider";
import { GoogleAnalyticsScripts } from "../../components/analytics/GoogleAnalyticsScripts";
import { GaPageViewTracker } from "../../components/analytics/GaPageViewTracker";
import { WebVitalsReporter } from "../../components/analytics/WebVitalsReporter";
import CookieBanner from "../../components/CookieBanner";
import { SchemaOrg } from "../../components/SchemaOrg";

import { METADATA_BASE, SHARED_ICONS, SHARED_OPEN_GRAPH } from "../../lib/metadata-shared";

const LOCALE = "fr" as const;

export const metadata = {
metadataBase: METADATA_BASE,
title: "PDFLince - Fusionner, Compresser, Diviser et Convertir des PDF",
description: "Outils PDF gratuits en ligne pour fusionner, compresser, diviser, extraire et convertir. 100% privé, traitement local dans votre navigateur.",
icons: SHARED_ICONS,
alternates: {
canonical: "https://pdflince.com/fr",
languages: {
'es-ES': 'https://pdflince.com',
'es-MX': 'https://pdflince.com',
'es-CO': 'https://pdflince.com',
'es-AR': 'https://pdflince.com',
'es': 'https://pdflince.com',
'en': 'https://pdflince.com/en',
'en-US': 'https://pdflince.com/en',
'fr': 'https://pdflince.com/fr',
'fr-FR': 'https://pdflince.com/fr',
'pt': 'https://pdflince.com/pt',
'pt-BR': 'https://pdflince.com/pt',
'de': 'https://pdflince.com/de',
'de-DE': 'https://pdflince.com/de',
'it': 'https://pdflince.com/it',
'it-IT': 'https://pdflince.com/it',
'x-default': 'https://pdflince.com',
},
},
openGraph: {
...SHARED_OPEN_GRAPH,
title: "PDFLince - Outils PDF gratuits et privés dans votre navigateur",
description: "Fusionnez, compressez, divisez et convertissez des PDF sans télécharger de fichiers. Sécurisé et 100% privé.",
url: "https://pdflince.com/fr",
locale: "fr_FR",
type: "website",
},
};

export default function FrLayout({ children }: { children: ReactNode }) {
return (
<html lang={LOCALE}>
<head>
<GoogleAnalyticsScripts />
<SchemaOrg />
</head>
<body className={`font-sans ${GeistSans.variable} ${GeistMono.variable}`}>
<LocaleProvider locale={LOCALE}>
<WebVitalsReporter />
<Suspense fallback={null}>
<GaPageViewTracker />
</Suspense>
<NavMenu />
<main>{children}</main>
<FotoLinceBanner />
<Footer />
<CookieBanner />
</LocaleProvider>
</body>
</html>
);
}
12 changes: 12 additions & 0 deletions src/app/fr/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { HomePageContent } from "../../components/HomePageContent";
import { getDictionary } from "../../i18n/get-dictionary";
import { createHomeMetadata } from "../(helpers)/locale-metadata";

const LOCALE = "fr" as const;

export const generateMetadata = createHomeMetadata(LOCALE);

export default function FrHomePage() {
const dictionary = getDictionary(LOCALE);
return <HomePageContent dictionary={dictionary} />;
}
10 changes: 10 additions & 0 deletions src/app/fr/support/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { SupportPageContent } from "../../../components/SupportPageContent";
import { createSupportMetadata } from "../../(helpers)/locale-metadata";

const LOCALE = "fr" as const;

export const generateMetadata = createSupportMetadata(LOCALE);

export default function FrSupportPage() {
return <SupportPageContent />;
}
2 changes: 2 additions & 0 deletions src/app/it/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export const metadata = {
'es': 'https://pdflince.com',
'en': 'https://pdflince.com/en',
'en-US': 'https://pdflince.com/en',
'fr': 'https://pdflince.com/fr',
'fr-FR': 'https://pdflince.com/fr',
'pt': 'https://pdflince.com/pt',
'pt-BR': 'https://pdflince.com/pt',
'de': 'https://pdflince.com/de',
Expand Down
2 changes: 2 additions & 0 deletions src/app/pt/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export const metadata = {
'es': 'https://pdflince.com',
'en': 'https://pdflince.com/en',
'en-US': 'https://pdflince.com/en',
'fr': 'https://pdflince.com/fr',
'fr-FR': 'https://pdflince.com/fr',
'pt': 'https://pdflince.com/pt',
'pt-BR': 'https://pdflince.com/pt',
'de': 'https://pdflince.com/de',
Expand Down
7 changes: 1 addition & 6 deletions src/app/robots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ export const revalidate = false;
export default function robots(): MetadataRoute.Robots {
const baseUrl = "https://pdflince.com";

// Cast to bypass Next.js restricted Sitemap type since it doesn't officially support 'host' yet
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const robotsObj: any = {
return {
rules: {
userAgent: "*",
allow: "/",
Expand All @@ -17,8 +15,5 @@ export default function robots(): MetadataRoute.Robots {
],
},
sitemap: `${baseUrl}/sitemap.xml`,
host: "pdflince.com",
};

return robotsObj as MetadataRoute.Robots;
}
Loading
Loading