feat(i18n): add Indonesian (id) locale#670
feat(i18n): add Indonesian (id) locale#670epromite wants to merge 1 commit intodiscord-tickets:mainfrom
Conversation
- Add full Indonesian (Bahasa Indonesia) translation (id.yml)
📝 WalkthroughWalkthroughA new Indonesian localization file is added containing UI string translations across buttons, commands, modals, menus, and related responses. The file includes emojis, titles, descriptions, and dynamic placeholders for user, ticket, category, and time values. No functional logic or control flow changes are introduced. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/i18n/id.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (1)
src/i18n/id.yml (1)
1-324: Well-structured Indonesian localization file.The YAML structure is syntactically valid with proper indentation and consistent organization. The translations cover all major sections (buttons, commands, ticket lifecycle, modals, misc, menus) with appropriate emojis and placeholders.
| buttons: | ||
| create: | ||
| emoji: 🎫 | ||
| text: Buat Tiket | ||
| edit: | ||
| emoji: ✏️ | ||
| text: Edit | ||
| reject_close_request: | ||
| emoji: ✖️ | ||
| text: Tolak | ||
| unclaim: | ||
| emoji: ♻️ | ||
| text: Lepas Penugasan | ||
| accept_close_request: | ||
| emoji: ✅ | ||
| text: Terima | ||
| cancel: | ||
| emoji: ➖ | ||
| text: Batal | ||
| claim: | ||
| emoji: 🙌 | ||
| text: Ambil Tiket | ||
| close: | ||
| emoji: ✖️ | ||
| text: Tutup | ||
| confirm_open: | ||
| emoji: ✅ | ||
| text: Buat Tiket | ||
|
|
||
| commands: | ||
| message: | ||
| create: | ||
| name: Buat tiket dari pesan | ||
| pin: | ||
| not_ticket: | ||
| title: ❌ Bukan Channel Tiket | ||
| description: Pesan hanya dapat disematkan di channel tiket. | ||
| not_pinnable: | ||
| title: ❌ Error | ||
| description: "Pesan ini tidak dapat disematkan.\nSilakan hubungi admin untuk memeriksa izin bot.\n" | ||
| name: Sematkan pesan | ||
| pinned: | ||
| title: ✅ Pesan Disematkan | ||
| description: Pesan berhasil disematkan. | ||
|
|
||
| slash: | ||
| add: | ||
| name: tambah-member | ||
| description: Menambahkan member ke tiket | ||
| success: | ||
| title: ✅ Ditambahkan | ||
| description: '{member} telah ditambahkan ke {ticket}.' | ||
| added: ➡️ {added} ditambahkan ke tiket oleh {by}. | ||
| not_staff: | ||
| title: ❌ Error | ||
| description: Hanya admin yang dapat menambahkan member ke tiket. | ||
| options: | ||
| member: | ||
| name: member | ||
| description: Member yang akan ditambahkan | ||
| ticket: | ||
| name: tiket | ||
| description: Tiket tujuan | ||
|
|
||
| force-close: | ||
| name: paksa-tutup | ||
| description: Menutup tiket secara paksa | ||
| no_tickets: | ||
| title: ❌ Tidak Ada Tiket | ||
| description: Tidak ada tiket tanpa aktivitas selama `{time}`. | ||
| closed_one: | ||
| title: ✅ Tiket Ditutup | ||
| description: Channel akan dihapus dalam beberapa detik. | ||
| confirmed_multiple: | ||
| title: | ||
| - ✅ %d Tiket Ditutup | ||
| - ✅ %d Tiket Ditutup | ||
| description: Channel akan dihapus dalam beberapa detik. | ||
| confirm_multiple: | ||
| title: ❓ Apakah Anda yakin? | ||
| description: "Akan menutup **{count}** tiket yang tidak aktif selama `{time}`:\n{tickets}\n" | ||
| not_staff: | ||
| title: ❌ Error | ||
| description: Hanya admin yang dapat menutup tiket secara paksa. | ||
| options: | ||
| category: | ||
| name: kategori | ||
| description: Tutup semua tiket di kategori (wajib isi waktu) | ||
| reason: | ||
| name: alasan | ||
| description: Alasan penutupan | ||
| ticket: | ||
| name: tiket | ||
| description: Tiket yang akan ditutup | ||
| time: | ||
| name: waktu | ||
| description: Tutup tiket tanpa aktivitas selama waktu tertentu | ||
|
|
||
| claim: | ||
| name: ambil | ||
| description: Mengambil tiket ini | ||
| not_staff: | ||
| title: ❌ Error | ||
| description: Hanya admin yang dapat mengambil tiket. | ||
|
|
||
| close: | ||
| name: tutup | ||
| description: Meminta penutupan tiket | ||
| invalid_time: | ||
| title: ❌ Tidak Valid | ||
| description: '`{input}` bukan format waktu yang valid.' | ||
| options: | ||
| reason: | ||
| name: alasan | ||
| description: Alasan penutupan tiket | ||
|
|
||
| help: | ||
| name: bantuan | ||
| description: Menampilkan menu bantuan | ||
| title: Bantuan | ||
| response: | ||
| commands: Perintah | ||
| description: '**Untuk mendapatkan bantuan, gunakan {command} untuk membuat tiket.**' | ||
| links: | ||
| commands: Semua Perintah | ||
| feedback: Feedback | ||
| links: Tautan Berguna | ||
| support: Support | ||
| docs: Dokumentasi | ||
| settings: Pengaturan Bot | ||
|
|
||
| move: | ||
| name: pindah | ||
| description: Memindahkan tiket ke kategori lain | ||
| moved: 🗃️ {by} memindahkan tiket ini dari **{from}** ke **{to}**. | ||
| not_staff: | ||
| title: ❌ Error | ||
| description: Hanya admin yang dapat memindahkan tiket. | ||
| options: | ||
| category: | ||
| name: kategori | ||
| description: Kategori tujuan | ||
|
|
||
| priority: | ||
| name: prioritas | ||
| description: Mengatur prioritas tiket | ||
| options: | ||
| priority: | ||
| name: prioritas | ||
| description: Prioritas tiket | ||
| choices: | ||
| LOW: 🟢 Rendah | ||
| MEDIUM: 🟠 Sedang | ||
| HIGH: 🔴 Tinggi | ||
| success: | ||
| title: ✅ Prioritas Diatur | ||
| description: Prioritas tiket diatur ke `{priority}`. | ||
| not_staff: | ||
| title: ❌ Error | ||
| description: Hanya admin yang dapat mengubah prioritas. | ||
|
|
||
| release: | ||
| name: lepas | ||
| description: Melepaskan penugasan tiket | ||
|
|
||
| remove: | ||
| name: hapus-member | ||
| description: Menghapus member dari tiket | ||
| success: | ||
| title: ✅ Dihapus | ||
| description: '{member} telah dihapus dari {ticket}.' | ||
| removed: ⬅️ {removed} dihapus dari tiket oleh {by}. | ||
| not_staff: | ||
| title: ❌ Error | ||
| description: Hanya admin yang dapat menghapus member. | ||
| options: | ||
| member: | ||
| name: member | ||
| description: Member yang akan dihapus | ||
| ticket: | ||
| name: tiket | ||
| description: Tiket tujuan | ||
|
|
||
| tickets: | ||
| name: tiket | ||
| description: Melihat daftar tiket | ||
| not_staff: | ||
| title: ❌ Error | ||
| description: Hanya admin yang dapat melihat tiket member lain. | ||
| options: | ||
| member: | ||
| name: member | ||
| description: Member target | ||
| response: | ||
| title: | ||
| own: Tiket Saya | ||
| other: Tiket {displayName} | ||
| description: Gunakan {transcript} untuk mengunduh salinan tiket. | ||
| fields: | ||
| open: | ||
| name: Tiket Terbuka | ||
| closed: | ||
| name: Tiket Ditutup | ||
| none: | ||
| own: "Anda belum pernah membuat tiket.\nGunakan {new} untuk membuat tiket baru.\n" | ||
| other: '{user} belum pernah membuat tiket.' | ||
|
|
||
| transfer: | ||
| name: pindah-kepemilikan | ||
| description: Memindahkan kepemilikan tiket | ||
| transferred: 📨 {user} memindahkan tiket ini ke {to}. | ||
| transferred_from: 📨 {user} memindahkan tiket dari {from} ke {to}. | ||
| options: | ||
| member: | ||
| name: member | ||
| description: Member tujuan | ||
|
|
||
| transcript: | ||
| name: transkrip | ||
| description: Mengunduh salinan tiket | ||
| not_staff: | ||
| title: ❌ Error | ||
| description: Hanya admin yang dapat melihat transkrip member lain. | ||
| options: | ||
| member: | ||
| name: member | ||
| description: Member target | ||
| ticket: | ||
| name: tiket | ||
| description: Tiket target | ||
|
|
||
| new: | ||
| name: tiket-baru | ||
| description: Membuat tiket baru | ||
| options: | ||
| references: | ||
| name: referensi-tiket | ||
| description: Nomor tiket terkait | ||
|
|
||
| tag: | ||
| name: tag | ||
| description: Menggunakan tag | ||
| options: | ||
| tag: | ||
| name: tag | ||
| description: Nama tag | ||
| for: | ||
| name: target | ||
| description: Member target | ||
|
|
||
| topic: | ||
| name: topik | ||
| description: Mengubah topik tiket | ||
|
|
||
| user: | ||
| create: | ||
| name: buat-tiket-untuk-member | ||
| not_staff: | ||
| title: ❌ Error | ||
| description: Hanya admin yang dapat membuka tiket untuk member lain. | ||
| sent: | ||
| title: ✅ Prompt Dikirim | ||
| description: '{user} diundang untuk membuat tiket di **{category}**.' | ||
| prompt: | ||
| title: Silakan buat tiket | ||
| description: Tekan tombol di bawah untuk membuat tiket. | ||
|
|
||
| ticket: | ||
| created: | ||
| title: ✅ Tiket Dibuat | ||
| description: Tiket {channel} berhasil dibuat. | ||
| edited: | ||
| title: ✅ Tiket Diperbarui | ||
| description: Perubahan berhasil disimpan. | ||
| closed: | ||
| title: ✅ Tiket Ditutup | ||
| description: Channel akan dihapus dalam beberapa detik… | ||
| claimed: 🙌 {user} mengambil tiket ini. | ||
| released: ♻️ {user} melepas penugasan tiket ini. | ||
| feedback: Terima kasih atas feedback Anda. | ||
| answers: | ||
| no_value: '*Tidak ada jawaban*' | ||
|
|
||
| modals: | ||
| topic: | ||
| label: Topik | ||
| placeholder: Apa topik tiket ini? | ||
| feedback: | ||
| title: Apakah ini membantu? | ||
| rating: | ||
| label: Penilaian | ||
| placeholder: 1-5 | ||
| comment: | ||
| label: Komentar | ||
| placeholder: Ada komentar tambahan? | ||
|
|
||
| misc: | ||
| ratelimited: | ||
| title: 🐢 Terlalu Cepat | ||
| description: Silakan coba lagi dalam beberapa detik. | ||
| not_ticket: | ||
| title: ❌ Bukan Channel Tiket | ||
| description: Perintah ini hanya dapat digunakan di channel tiket. | ||
| cooldown: | ||
| title: ❌ Tunggu Sebentar | ||
| description: Coba lagi dalam {time} detik. | ||
| blocked: | ||
| title: ❌ Diblokir | ||
| description: Anda tidak diizinkan membuat tiket. | ||
| expired: | ||
| title: ⏰ Kedaluwarsa | ||
| description: Waktu habis. Silakan coba lagi. | ||
| unknown_category: | ||
| title: ❌ Kategori Tidak Ditemukan | ||
| description: Silakan masukkan kategori yang valid. | ||
| invalid_ticket: | ||
| title: ❌ Tiket Tidak Valid | ||
| description: Silakan masukkan tiket yang valid. | ||
|
|
||
| menus: | ||
| guild: | ||
| placeholder: Pilih Server | ||
| category: | ||
| placeholder: Pilih Kategori Tiket |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's find all locale files in the repository
find . -path ./node_modules -prune -o -name "*.yml" -type f | grep -i i18n | head -20Repository: discord-tickets/bot
Length of output: 445
🏁 Script executed:
#!/bin/bash
# Extract all YAML keys from a file using Python for proper YAML parsing
extract_yaml_keys() {
python3 - "$1" <<'PYEOF'
import sys
import yaml
def get_all_keys(data, prefix=''):
"""Recursively extract all keys from nested dict"""
keys = []
if isinstance(data, dict):
for k, v in data.items():
full_key = f"{prefix}.{k}" if prefix else k
keys.append(full_key)
if isinstance(v, dict):
keys.extend(get_all_keys(v, full_key))
return keys
try:
with open(sys.argv[1], 'r', encoding='utf-8') as f:
data = yaml.safe_load(f)
keys = sorted(get_all_keys(data))
for key in keys:
print(key)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
PYEOF
}
echo "Extracting keys from en-GB.yml (reference)..."
ref_keys=$(extract_yaml_keys src/i18n/en-GB.yml)
ref_count=$(echo "$ref_keys" | wc -l)
echo "Total keys in reference: $ref_count"
echo -e "\nExtracting keys from id.yml (Indonesian)..."
id_keys=$(extract_yaml_keys src/i18n/id.yml)
id_count=$(echo "$id_keys" | wc -l)
echo "Total keys in Indonesian: $id_count"
echo -e "\n=== KEYS IN REFERENCE BUT MISSING IN INDONESIAN ==="
missing=$(comm -23 <(echo "$ref_keys") <(echo "$id_keys"))
missing_count=$(echo "$missing" | grep -c . || echo 0)
echo "Missing keys: $missing_count"
if [ "$missing_count" -gt 0 ]; then
echo "$missing" | head -30
if [ "$missing_count" -gt 30 ]; then
echo "... and $((missing_count - 30)) more"
fi
fi
echo -e "\n=== KEYS IN INDONESIAN BUT NOT IN REFERENCE ==="
extra=$(comm -13 <(echo "$ref_keys") <(echo "$id_keys"))
extra_count=$(echo "$extra" | grep -c . || echo 0)
echo "Extra keys: $extra_count"
if [ "$extra_count" -gt 0 ]; then
echo "$extra" | head -30
if [ "$extra_count" -gt 30 ]; then
echo "... and $((extra_count - 30)) more"
fi
fiRepository: discord-tickets/bot
Length of output: 565
🏁 Script executed:
#!/bin/bash
# Extract all YAML keys from a file using Python for proper YAML parsing
extract_yaml_keys() {
python3 - "$1" <<'PYEOF'
import sys
import yaml
def get_all_keys(data, prefix=''):
"""Recursively extract all keys from nested dict"""
keys = []
if isinstance(data, dict):
for k, v in data.items():
full_key = f"{prefix}.{k}" if prefix else k
keys.append(full_key)
if isinstance(v, dict):
keys.extend(get_all_keys(v, full_key))
return keys
try:
with open(sys.argv[1], 'r', encoding='utf-8') as f:
data = yaml.safe_load(f)
keys = sorted(get_all_keys(data))
for key in keys:
print(key)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
PYEOF
}
echo "Extracting and comparing keys..."
ref_keys=$(extract_yaml_keys src/i18n/en-GB.yml | sort)
id_keys=$(extract_yaml_keys src/i18n/id.yml | sort)
ref_count=$(echo "$ref_keys" | wc -l)
id_count=$(echo "$id_keys" | wc -l)
echo "Reference (en-GB.yml): $ref_count keys"
echo "Indonesian (id.yml): $id_count keys"
echo -e "\n=== MISSING KEYS IN INDONESIAN ==="
# Find missing keys using grep
missing=()
while IFS= read -r key; do
if ! echo "$id_keys" | grep -Fxq "$key"; then
missing+=("$key")
fi
done <<< "$ref_keys"
missing_count=${#missing[@]}
echo "Missing keys: $missing_count"
echo ""
# Display first 40 missing keys
for ((i = 0; i < missing_count && i < 40; i++)); do
echo "${missing[$i]}"
done
if [ "$missing_count" -gt 40 ]; then
echo "... and $((missing_count - 40)) more missing keys"
fiRepository: discord-tickets/bot
Length of output: 1369
Add 162 missing translation keys to match reference locale.
The Indonesian locale is missing 162 keys compared to the reference English locale (en-GB.yml: 460 keys vs id.yml: 301 keys). Missing keys include:
buttons.transcript(emoji and text)commands.slash.renameand all its sub-keysdmsection (closed, confirm_open, etc.)logsection- 122 additional keys
Without these translations, users will see untranslated text or English fallbacks. Compare id.yml against src/i18n/en-GB.yml and add all missing keys with Indonesian translations.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Extract all placeholders from the new Indonesian file and compare with an existing locale file
echo "=== Placeholders in id.yml ==="
rg -o '\{[a-zA-Z_]+\}' src/i18n/id.yml | sort -u
echo -e "\n=== Checking available locale files ==="
fd -e yml . src/i18n --max-depth 1
echo -e "\n=== Placeholders in reference locale (en-GB.yml) ==="
if [ -f src/i18n/en-GB.yml ]; then
rg -o '\{[a-zA-Z_]+\}' src/i18n/en-GB.yml | sort -u
elif [ -f src/i18n/en-US.yml ]; then
echo "Using en-US.yml instead"
rg -o '\{[a-zA-Z_]+\}' src/i18n/en-US.yml | sort -u
else
echo "No reference English locale file found, checking for any .yml files"
ls -la src/i18n/
fiRepository: discord-tickets/bot
Length of output: 1153
🏁 Script executed:
#!/bin/bash
# Compare the top-level keys between id.yml and en-GB.yml to check if sections are missing
echo "=== Top-level keys in id.yml ==="
rg '^[a-zA-Z_]+:' src/i18n/id.yml | sed 's/:$//' | sort -u
echo -e "\n=== Top-level keys in en-GB.yml ==="
rg '^[a-zA-Z_]+:' src/i18n/en-GB.yml | sed 's/:$//' | sort -uRepository: discord-tickets/bot
Length of output: 223
🏁 Script executed:
#!/bin/bash
# Check the dm and log sections in en-GB.yml to see if they're essential
echo "=== dm section in en-GB.yml ==="
sed -n '/^dm:/,/^[a-zA-Z]/p' src/i18n/en-GB.yml | head -50
echo -e "\n=== log section in en-GB.yml ==="
sed -n '/^log:/,/^[a-zA-Z]/p' src/i18n/en-GB.yml | head -50Repository: discord-tickets/bot
Length of output: 1496
Add missing dm and log sections for complete Indonesian localization.
The Indonesian locale file is incomplete. While all placeholder variables are consistent with the English reference, the file is missing two top-level sections present in en-GB.yml:
dm: Direct message content for ticket closure notifications and confirmation promptslog: Admin logging and audit trail strings (includes placeholders {user}, {verb}, {targetType}, {timestamp}, {duration})
These sections should be translated and added to maintain parity with the English localization.
🤖 Prompt for AI Agents
In src/i18n/id.yml around lines 1-324, the file is missing the top-level dm and
log sections present in en-GB.yml; add translated dm (direct-message prompts for
ticket closure/confirmation and related notifications) and log (admin/audit
trail messages) sections using the same keys as en-GB.yml, preserve all
placeholders ({user}, {verb}, {targetType}, {timestamp}, {duration}, etc.),
ensure YAML structure and indentation match existing file, and provide accurate
Indonesian translations for each string so localization parity is restored.
| closed: | ||
| name: Tiket Ditutup | ||
| none: | ||
| own: "Anda belum pernah membuat tiket.\nGunakan {new} untuk membuat tiket baru.\n" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check the actual structure of src/i18n/id.yml around line 205
echo "=== Examining src/i18n/id.yml around line 205 ==="
sed -n '200,210p' src/i18n/id.yml | cat -A
echo ""
echo "=== Looking for tickets response structure in id.yml ==="
rg -n "tickets:" src/i18n/id.yml -A 40 | head -60Repository: discord-tickets/bot
Length of output: 2577
🏁 Script executed:
#!/bin/bash
# Check similar patterns across all locale files
echo "=== Checking tickets.response.fields in all locale files ==="
fd -e yml -e yaml . src/i18n --exec basename {} \; | sort | while read file; do
echo "File: $file"
rg -n "tickets:" "src/i18n/$file" -A 40 | grep -E "(none:|own:)" | head -5
doneRepository: discord-tickets/bot
Length of output: 2985
🏁 Script executed:
#!/bin/bash
# Search for where these locale strings are actually used
echo "=== Searching for usage of tickets.response or message rendering logic ==="
rg -r "tickets.*response" --type js --type ts src/ -A 2 -B 2 | head -40
echo ""
echo "=== Looking for locale string loading/processing ==="
rg -r "\.own|locale|yml|i18n" --type js --type ts src/ | grep -E "(load|parse|message|embed)" | head -30Repository: discord-tickets/bot
Length of output: 1993
🏁 Script executed:
#!/bin/bash
# Check how the bot handles embed descriptions or message content
echo "=== Searching for embed.description or similar field handling ==="
rg "description" --type js --type ts src/ -B 2 -A 2 | grep -E "(description|setDescription|\.own)" | head -40
echo ""
echo "=== Look for the tickets command implementation ==="
fd -e js -e ts . src/commands --exec grep -l "tickets" {} \;Repository: discord-tickets/bot
Length of output: 4475
🏁 Script executed:
#!/bin/bash
# Read the tickets command implementation
echo "=== Reading src/commands/slash/tickets.js ==="
cat -n src/commands/slash/tickets.jsRepository: discord-tickets/bot
Length of output: 7026
🏁 Script executed:
#!/bin/bash
# Search for getMessage implementation
echo "=== Finding getMessage function ==="
rg "function getMessage|const getMessage|export.*getMessage" --type js --type ts -B 2 -A 10 src/Repository: discord-tickets/bot
Length of output: 39605
🏁 Script executed:
#!/bin/bash
# Find the i18n implementation
echo "=== Searching for i18n implementation ==="
fd -e js -e ts . src/lib --exec grep -l "getMessage\|getLocale\|i18n" {} \;
echo ""
echo "=== Look for i18n class/module ==="
rg "class.*i18n|export.*getMessage|getLocale.*function" --type js --type ts src/ -B 2 -A 8 | head -100Repository: discord-tickets/bot
Length of output: 264
🏁 Script executed:
#!/bin/bash
# Check if there's i18n configuration or module in lib
echo "=== Checking lib directory structure ==="
ls -la src/lib/ | grep -i i18n
echo ""
echo "=== Search for where i18n is initialized ==="
rg "new.*i18n|i18n.*=|require.*i18n" --type js src/ -B 2 -A 3 | head -60Repository: discord-tickets/bot
Length of output: 3190
🏁 Script executed:
#!/bin/bash
# Check if @eartharoid/i18n is in node_modules or package.json
echo "=== Checking package.json for i18n library ==="
cat package.json | grep -A 5 -B 5 "eartharoid"
echo ""
echo "=== Look for any string processing/trimming in client.js ==="
rg -n "i18n|getLocale|getMessage" src/client.js -B 3 -A 10Repository: discord-tickets/bot
Length of output: 2824
🏁 Script executed:
#!/bin/bash
# Check if @eartharoid/i18n is documented or if we can find info about it
# Also search for any .trim() calls in the codebase when using getMessage
echo "=== Searching for any .trim() usage with getMessage ==="
rg "getMessage.*\.trim|\.trim.*getMessage" --type js src/
echo ""
echo "=== Check how field values are processed in tickets.js context ==="
sed -n '135,145p' src/commands/slash/tickets.js | cat -ARepository: discord-tickets/bot
Length of output: 664
🏁 Script executed:
#!/bin/bash
# Let's check if there's a web reference or look for how the YAML string is actually stored
echo "=== Verify exact YAML parsing of the trailing newline ==="
python3 << 'EOF'
import yaml
# Simulate what happens when the YAML is parsed
yaml_content = '''
tickets:
response:
fields:
closed:
none:
own: "Anda belum pernah membuat tiket.\nGunakan {new} untuk membuat tiket baru.\n"
'''
parsed = yaml.safe_load(yaml_content)
own_string = parsed['tickets']['response']['fields']['closed']['none']['own']
print(f"String value: {repr(own_string)}")
print(f"Ends with newline: {own_string.endswith(chr(10))}")
print(f"String length: {len(own_string)}")
print(f"Last 5 chars: {repr(own_string[-5:])}")
EOFRepository: discord-tickets/bot
Length of output: 275
🏁 Script executed:
#!/bin/bash
# Let's extract the exact line from the file and test it
echo "=== Extract exact YAML line from id.yml ==="
sed -n '205p' src/i18n/id.yml | od -c | head -20
echo ""
echo "=== Test with actual extracted content ==="
python3 << 'EOF'
import yaml
import subprocess
# Get the actual line from the file
result = subprocess.run(['sed', '-n', '205p', 'src/i18n/id.yml'], capture_output=True, text=True)
line = result.stdout
print(f"Raw line from file: {repr(line)}")
# Extract just the value part and parse
yaml_test = line.strip()
if yaml_test.startswith('own:'):
# Parse the whole line as YAML
parsed = yaml.safe_load('temp:\n ' + yaml_test)
value = parsed['temp']['own']
print(f"\nParsed string repr: {repr(value)}")
print(f"Ends with newline char: {value.endswith(chr(10))}")
print(f"Last char code: {ord(value[-1])}")
EOFRepository: discord-tickets/bot
Length of output: 478
🏁 Script executed:
#!/bin/bash
# Let's verify how the other locales handle this same field to understand the pattern better
echo "=== Compare trailing character patterns across locales ==="
python3 << 'EOF'
import yaml
import subprocess
locales = ['id', 'da', 'es-ES', 'hu', 'ko', 'pl', 'th', 'en-GB', 'fr']
for locale in locales:
try:
result = subprocess.run(['rg', '-n', 'closed:', f'src/i18n/{locale}.yml', '-A', '5'],
capture_output=True, text=True, timeout=5)
if result.returncode == 0 and result.stdout:
lines = result.stdout.split('\n')
for line in lines:
if 'own:' in line and 'none:' in lines[max(0, lines.index(line)-2):lines.index(line)]:
print(f"\n{locale}: {line.strip()}")
# Extract value
if 'own:' in line:
value_part = line.split('own:', 1)[1].strip()
if value_part.startswith('"'):
# Count trailing whitespace in quoted strings
print(f" Type: quoted string")
elif value_part.startswith('|'):
print(f" Type: YAML pipe (multi-line)")
except:
pass
EOFRepository: discord-tickets/bot
Length of output: 121
🏁 Script executed:
#!/bin/bash
# Simpler approach - just check the exact lines where the "own" field is for closed.none
echo "=== Extract own field from multiple locale files ==="
for locale in id da es-ES hu ko pl th en-GB it fr; do
echo "=== $locale.yml ==="
grep -n "own:" src/i18n/${locale}.yml | grep -A 1 -B 1 "205\|206\|207\|208" || grep -n "own:" src/i18n/${locale}.yml | tail -5
doneRepository: discord-tickets/bot
Length of output: 1520
🏁 Script executed:
#!/bin/bash
# Check specific lines in a few key locale files for the exact content
echo "=== Checking exact content of closed.none.own field ==="
python3 << 'EOF'
import yaml
locales_to_check = ['id', 'da', 'es-ES', 'hu', 'ko', 'en-GB', 'it']
for locale in locales_to_check:
try:
with open(f'src/i18n/{locale}.yml', 'r', encoding='utf-8') as f:
data = yaml.safe_load(f)
try:
own_field = data['commands']['slash']['tickets']['response']['fields']['closed']['none']['own']
ends_with_newline = own_field.endswith('\n')
ends_with_space = own_field.endswith(' ')
print(f"{locale:10} | ends with newline: {ends_with_newline:5} | ends with space: {ends_with_space:5} | last 20 chars: {repr(own_field[-20:])}")
except (KeyError, TypeError):
print(f"{locale:10} | Field not found")
except FileNotFoundError:
print(f"{locale:10} | File not found")
EOFRepository: discord-tickets/bot
Length of output: 846
Remove trailing newline from field value.
The string ends with \n which will cause unwanted spacing in Discord message embeds. This pattern affects multiple locales (id, da, es-ES, hu, ko, pl, th, fr, and others) for the commands.slash.tickets.response.fields.closed.none.own field. Either remove the trailing \n from the quoted string or switch to YAML multiline syntax (|-) which strips the final newline.
🤖 Prompt for AI Agents
In src/i18n/id.yml around line 205, the value for
commands.slash.tickets.response.fields.closed.none.own ends with a trailing "\n"
which produces unwanted spacing in Discord embeds; remove the trailing newline
from the quoted string (change "...baru.\n" to "...baru.") or convert the value
to YAML block scalar that strips the final newline (use the |- block style) so
the message no longer includes the extra line break.
Versioning information
Is this related to an issue?
Changes made
Confirmations
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.