Skip to content

Conversation

@notthebestdev
Copy link
Owner

@notthebestdev notthebestdev commented Jan 1, 2026

Warning

This PR is still an W.I.P

  • Translate commands based on the server's language

- Introduced various error messages and notifications
- Enhanced user feedback for permissions and bot status
- Adds `ky` for making HTTP requests with improved syntax.
- Adds `yaml` for parsing YAML configuration files.
- Refactors member fetching to use `ky` for improved readability and conciseness.
- Introduces a utility function to retrieve localization files based on the specified language.
- Supports French and defaults to English localization.
- Replaces double quotes with single quotes in the English locale file for consistency.
- Corrects the file path for locale files and updates the type definition.
- Implements internationalization (i18n) for bot responses.
- Uses YAML files to store translations.
- Retrieves server language and uses it to display messages.
- Adds `en.yml` with default messages.
- Removes an unused import to improve code cleanliness.
- Eliminates `parse` from `yaml` as it is no longer needed.
- Adds the `nodejs_compat` compatibility flag to the Wrangler configuration.
- Updates the generated types to include NodeJS process environment variables.
- This allows the worker to access NodeJS-compatible APIs.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds internationalization (i18n) support to enable Discord bot commands to respond in the server's preferred language. The implementation includes language detection from Discord guilds and YAML-based localization files for English and French.

Key changes:

  • Added utility functions to fetch server language from Discord API and load localization files
  • Created YAML-based localization files for English and French translations
  • Integrated localization into command handlers for /help, /someone, and /ping commands

Reviewed changes

Copilot reviewed 8 out of 10 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
wrangler.jsonc Added nodejs_compat compatibility flag to enable Node.js APIs
worker-configuration.d.ts Auto-generated type definitions updated to reflect the new compatibility flag
src/utils/getLanguageFromServer.ts New utility to fetch guild language preference from Discord API
src/utils/getFileFromLanguage.ts New utility to load YAML localization files based on language code
src/types/fileLanguage.ts TypeScript interface defining the structure of localization strings
src/locales/fr.yml French translations for all bot messages and errors
src/locales/en.yml English translations for all bot messages and errors
src/index.ts Updated command handlers to load and use localized strings
package.json Added ky and yaml dependencies for HTTP requests and YAML parsing
package-lock.json Lockfile updated with new dependency entries

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 2 to 16
import fs from 'fs';
import path from 'path';
import type { FileLanguage } from '../types/fileLanguage';

export default function getFileFromLanguage(language: string): unknown {
let fileName: string;
switch (language) {
case 'fr':
fileName = 'fr.yml';
break;
default:
fileName = 'en.yml';
}
const filePath = path.resolve(__dirname, 'locales', fileName);
const fileContents = fs.readFileSync(filePath, 'utf8');
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using Node.js fs and path modules in a Cloudflare Workers environment will not work. Cloudflare Workers don't have access to the file system. You need to either bundle the YAML files as static assets or import them directly. Consider using Wrangler's asset binding or importing the YAML files at build time instead of reading them with fs.readFileSync at runtime.

Suggested change
import fs from 'fs';
import path from 'path';
import type { FileLanguage } from '../types/fileLanguage';
export default function getFileFromLanguage(language: string): unknown {
let fileName: string;
switch (language) {
case 'fr':
fileName = 'fr.yml';
break;
default:
fileName = 'en.yml';
}
const filePath = path.resolve(__dirname, 'locales', fileName);
const fileContents = fs.readFileSync(filePath, 'utf8');
import type { FileLanguage } from '../types/fileLanguage';
import enYaml from '../locales/en.yml';
import frYaml from '../locales/fr.yml';
export default function getFileFromLanguage(language: string): unknown {
let fileContents: string;
switch (language) {
case 'fr':
fileContents = frYaml;
break;
default:
fileContents = enYaml;
}

Copilot uses AI. Check for mistakes.
Comment on lines 25 to +35
// get guild id
const guildId = c.interaction.guild?.id;
if (!guildId) return c.res('<a:crossmark:1454281378295451648> **Guild not found.**');
if (!guildId) return c.res(lang.GUILD_NOT_FOUND);
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The guildId is checked and returned early on line 22, making this duplicate check on line 35 redundant and unreachable. The code comment "get guild id" is also misleading since the guildId was already retrieved earlier. Remove this redundant check.

Copilot uses AI. Check for mistakes.
const guildId = c.interaction.guild?.id;
const memberPermissions = c.interaction.member?.permissions;
if (!memberPermissions) return c.res('<a:crossmark:1454281378295451648> **Unable to verify permissions.**');
if (!guildId) return c.res('<a:crossmark:1454281378295451648> **Guild not found.**');
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The language loading happens after the first guild check. If guildId is null at line 22, the function returns before the language is loaded. Move the guildId null check after the language loading, or handle the error message using a default language. Currently, line 22 returns a hardcoded English error message even if the server uses French.

Copilot uses AI. Check for mistakes.
Comment on lines +79 to +83
let lang: FileLanguage = getFileFromLanguage('en') as FileLanguage;
const guildId = c.interaction.guild?.id as string;
await getLanguageFromServer(guildId, c).then((language) => {
lang = getFileFromLanguage(language) as FileLanguage;
});
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The language loading pattern is duplicated in three command handlers. Consider extracting this logic into a helper function or middleware to avoid code duplication and ensure consistent language loading behavior across all commands.

Copilot uses AI. Check for mistakes.
Comment on lines +24 to +26
await getLanguageFromServer(guildId, c).then((language) => {
lang = getFileFromLanguage(language) as FileLanguage;
});
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using .then() is unnecessary here since the code already uses await. You can simplify this to: const language = await getLanguageFromServer(guildId, c); lang = getFileFromLanguage(language) as FileLanguage;. This makes the code more readable and consistent with the async/await pattern used elsewhere.

Copilot uses AI. Check for mistakes.
searchParams: { limit: '1000' },
headers: { Authorization: `Bot ${token}` },
});
if (!resp.ok) return c.res(`Failed to fetch members: ${resp.status} ${resp.statusText}`);
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error responses should also be localized. This hardcoded error message "Failed to fetch members: {status} {statusText}" will always be in English, even if the server uses French. Consider adding this error message to the localization files.

Suggested change
if (!resp.ok) return c.res(`Failed to fetch members: ${resp.status} ${resp.statusText}`);
if (!resp.ok) return c.res(`${resp.status} ${resp.statusText}`);

Copilot uses AI. Check for mistakes.
notthebestdev and others added 3 commits January 1, 2026 17:33
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@notthebestdev notthebestdev added the enhancement New feature or request label Jan 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants