diff --git a/README.md b/README.md index 77f77fe..791d020 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,27 @@ Use it in apps, bots, landing pages, Slack integrations, rejection letters, or w --- +## 🌐 Language Support + +No-as-a-Service supports multiple languages based on the `Accept-Language` header: + +### Example Request with Language Preference +```http +GET /no +Accept-Language: fr +``` + +### Currently Supported Languages +- English (en) - Default +- German (de) +- French (fr) + +### Contributing Translations +We welcome contributions for new languages! Simply create a new JSON file in the `reasons` directory: +1. Name it using the 2-letter language code (e.g., `es.json` for Spanish) +2. Add your creative rejection phrases as a JSON array +3. Submit a pull request + ## 🛠️ Self-Hosting Want to run it yourself? It’s lightweight and simple. diff --git a/index.js b/index.js index 4c6d122..6f5c290 100644 --- a/index.js +++ b/index.js @@ -1,13 +1,52 @@ const express = require('express'); const rateLimit = require('express-rate-limit'); const fs = require('fs'); +const path = require('path'); const app = express(); app.set('trust proxy', true); const PORT = process.env.PORT || 3000; -// Load reasons from JSON -const reasons = JSON.parse(fs.readFileSync('./reasons.json', 'utf-8')); +function getAvailableLanguages() { + const langDir = path.join(__dirname, 'reasons'); + const files = fs.readdirSync(langDir); + + const languages = {}; + for (const file of files) { + if (file.endsWith('.json')) { + // Extract language code from filename (e.g., 'en.json' -> 'en') + const langCode = path.basename(file, '.json'); + languages[langCode] = file; + } + } + + return languages; +} + +const availableLanguages = getAvailableLanguages(); + +// Default language +const defaultLanguage = 'en'; + +// Load reasons based on language +function getReasons(lang) { + try { + const languageFile = availableLanguages[lang] || availableLanguages[defaultLanguage]; + const filePath = path.join(__dirname, 'reasons', languageFile); + + // Check if the file exists + if (fs.existsSync(filePath)) { + return JSON.parse(fs.readFileSync(filePath, 'utf-8')); + } + + // Fallback to English if file doesn't exist + return JSON.parse(fs.readFileSync(path.join(__dirname, 'reasons', availableLanguages[defaultLanguage]), 'utf-8')); + } catch (error) { + console.error(`Error loading language file: ${error}`); + // Return a single reason as emergency fallback + return ["Sorry, I can't do that right now."]; + } +} // Rate limiter: 120 requests per minute per IP const limiter = rateLimit({ @@ -23,11 +62,32 @@ app.use(limiter); // Random rejection reason endpoint app.get('/no', (req, res) => { + // Parse Accept-Language header + const acceptLanguage = req.headers['accept-language']; + let lang = defaultLanguage; + + if (acceptLanguage) { + // Extract language code (e.g., 'en-US' -> 'en') + const requestedLanguages = acceptLanguage.split(',') + .map(langQ => { + const [language, qValue] = langQ.trim().split(';'); + return language.substring(0, 2).toLowerCase(); // Get primary language tag + }); + + // Find the first requested language that's available + lang = requestedLanguages.find(l => availableLanguages[l]) || defaultLanguage; + } + + // Load reasons for the selected language + const reasons = getReasons(lang); + + // Pick a random reason const reason = reasons[Math.floor(Math.random() * reasons.length)]; + res.json({ reason }); }); // Start server app.listen(PORT, () => { console.log(`No-as-a-Service is running on port ${PORT}`); -}); +}); \ No newline at end of file diff --git a/reasons/de.json b/reasons/de.json new file mode 100644 index 0000000..46135bf --- /dev/null +++ b/reasons/de.json @@ -0,0 +1,7 @@ +[ + "Tut mir leid, aber ich muss leider ablehnen.", + "Das passt jetzt leider gar nicht in meinen Zeitplan.", + "Die Sterne stehen heute nicht günstig dafür.", + "Ich habe bereits zu viele Projekte am Laufen.", + "Mein innerer Schweinehund lässt grüßen und sagt nein." +] \ No newline at end of file diff --git a/reasons.json b/reasons/en.json similarity index 100% rename from reasons.json rename to reasons/en.json diff --git a/reasons/fr.json b/reasons/fr.json new file mode 100644 index 0000000..25d1fef --- /dev/null +++ b/reasons/fr.json @@ -0,0 +1,7 @@ +[ + "Je dois respectueusement décliner.", + "C'est une idée intéressante, mais ce n'est pas pour moi.", + "Mon agenda est malheureusement déjà bien rempli.", + "Je dois écouter ma voix intérieure, et elle me dit non.", + "Je préfère réserver mon énergie pour d'autres projets." +] \ No newline at end of file