This document describes the internationalization (i18n) implementation for the CSS & JS Minifier extension.
The extension uses VS Code's native localization system to provide a fully internationalized user experience across 7 languages. All user-facing text is translated, including commands, configuration settings, error messages, and notifications.
The extension currently supports:
| Language | Code | Package File | Runtime Bundle |
|---|---|---|---|
| English (Default) | en | package.nls.json |
l10n/bundle.l10n.json |
| Spanish | es | package.nls.es.json |
l10n/bundle.l10n.es.json |
| French | fr | package.nls.fr.json |
l10n/bundle.l10n.fr.json |
| German | de | package.nls.de.json |
l10n/bundle.l10n.de.json |
| Portuguese (Brazil) | pt-br | package.nls.pt-br.json |
l10n/bundle.l10n.pt-br.json |
| Japanese | ja | package.nls.ja.json |
l10n/bundle.l10n.ja.json |
| Chinese Simplified | zh-cn | package.nls.zh-cn.json |
l10n/bundle.l10n.zh-cn.json |
The extension uses two separate translation systems:
Used for static contributions in package.json:
- Command titles
- Configuration section titles
- Configuration setting descriptions
- Enum option descriptions
File Location: Root directory
Format: JSON key-value pairs
Usage in package.json: %key% syntax
Example:
// package.json
{
"contributes": {
"commands": [{
"command": "extension.minify",
"title": "%commands.extension.minify.title%"
}]
}
}
// package.nls.json (English)
{
"commands.extension.minify.title": "Minify this File"
}
// package.nls.es.json (Spanish)
{
"commands.extension.minify.title": "Minificar este archivo"
}Used for dynamic messages in TypeScript code:
- Error messages
- Success notifications
- Validation messages
- User feedback
File Location: l10n/ directory
Format: JSON key-value pairs with placeholder support
Usage in code: l10n.t('key', ...args)
Example:
// TypeScript code
import * as l10n from '@vscode/l10n';
vscode.window.showErrorMessage(
l10n.t('validators.fileType.unsupported', fileType)
);
// l10n/bundle.l10n.json (English)
{
"validators.fileType.unsupported": "File type '{0}' is not supported. Only CSS and JavaScript files can be minified."
}
// l10n/bundle.l10n.es.json (Spanish)
{
"validators.fileType.unsupported": "El tipo de archivo '{0}' no es compatible. Solo se pueden minificar archivos CSS y JavaScript."
}commands.extension.minify.title
commands.extension.minifyInNewFile.title
configuration.title
configuration.minifyOnSave
configuration.minifyInNewFile
configuration.minifiedNewFilePrefix
configuration.minifiedNewFilePrefix.enumDescriptions.1
configuration.minifiedNewFilePrefix.enumDescriptions.2
configuration.minifiedNewFilePrefix.enumDescriptions.3
configuration.minifiedNewFilePrefix.enumDescriptions.4
configuration.minifiedNewFilePrefix.enumDescriptions.5
configuration.minifiedNewFilePrefix.enumDescriptions.6
configuration.autoOpenNewFile
validators.fileType.unsupported
validators.content.empty
fileService.newFile.success
fileService.inPlace.success
minificationService.fileType.unsupported
minificationService.fileSize.tooLarge
minificationService.error.missingInput
minificationService.error.invalidMethod
minificationService.error.invalidContentType
minificationService.error.fileTooLarge
minificationService.error.invalidSyntax
minificationService.error.rateLimitExceeded
minificationService.error.apiError
minificationService.error.invalidResponse
minificationService.error.timeout
minificationService.error.network
minificationService.error.generic
Runtime messages support parameter interpolation using {0}, {1}, {2}, etc.
Examples:
// Single parameter
l10n.t('validators.fileType.unsupported', 'html')
// Result: "File type 'html' is not supported..."
// Multiple parameters
l10n.t('minificationService.error.apiError', 'CSS Minifier', '429', 'Too Many Requests')
// Result: "CSS Minifier API error (429): Too Many Requests"Three main modules were updated to use l10n:
src/utils/validators.ts
- 2 messages internationalized
- File type validation errors
- Content length validation errors
src/services/fileService.ts
- 2 messages internationalized
- Success notifications for file operations
src/services/minificationService.ts
- 13 messages internationalized
- API error messages
- Network error messages
- Validation error messages
import * as l10n from "@vscode/l10n";// Before (hardcoded)
vscode.window.showErrorMessage(
`File type '${fileType}' is not supported. Only CSS and JavaScript files can be minified.`
);
// After (internationalized)
vscode.window.showErrorMessage(
l10n.t('validators.fileType.unsupported', fileType)
);The extension includes comprehensive i18n tests in src/test/i18n.test.ts:
Test Coverage:
- File Existence: Verify all translation files exist
- JSON Validity: Ensure all files are valid JSON
- Key Consistency: All languages have the same keys
- Value Completeness: No empty or missing translations
- Placeholder Preservation: Translations maintain {0}, {1}, etc.
- VS Code Integration: Commands and config use i18n keys
- Translation Quality: No untranslated English text in other languages
Running i18n Tests:
# Run all i18n tests
npm run pretest
npx vscode-test --grep "Internationalization"
# Or use VS Code task
# Tasks: Run Task -> Test: Internationalization (i18n) Suite OnlyTo add support for a new language, follow these detailed steps:
Create package.nls.it.json in the root directory with all 13 keys:
{
"commands.extension.minify.title": "Minimizza questo file",
"commands.extension.minifyInNewFile.title": "Minimizza e salva come nuovo file",
"configuration.title": "Configurazione dello strumento di minimizzazione JS e CSS",
"configuration.minifyOnSave": "Minimizza automaticamente i file al salvataggio",
"configuration.minifyInNewFile": "Salva il contenuto minimizzato in un nuovo file",
"configuration.minifiedNewFilePrefix": "Prefisso per il nuovo file minimizzato. L'estensione sarà la stessa del file originale. Si applica solo quando si salva contenuto minimizzato in un nuovo file.",
"configuration.minifiedNewFilePrefix.enumDescriptions.1": "Il nome del nuovo file avrà l'estensione '.min'.",
"configuration.minifiedNewFilePrefix.enumDescriptions.2": "Il nome del nuovo file avrà l'estensione '-min'.",
"configuration.minifiedNewFilePrefix.enumDescriptions.3": "Il nome del nuovo file avrà l'estensione '.compressed'.",
"configuration.minifiedNewFilePrefix.enumDescriptions.4": "Il nome del nuovo file avrà l'estensione '-compressed'.",
"configuration.minifiedNewFilePrefix.enumDescriptions.5": "Il nome del nuovo file avrà l'estensione '.minified'.",
"configuration.minifiedNewFilePrefix.enumDescriptions.6": "Il nome del nuovo file avrà l'estensione '-minified'.",
"configuration.autoOpenNewFile": "Apri automaticamente i file minimizzati appena creati nell'editor."
}Key Points:
- Must have exactly 13 keys (same as other languages)
- Keys must match exactly (case-sensitive)
- Use native language translations
- Preserve technical terms in their standard form
Create l10n/bundle.l10n.it.json with all 17 runtime message keys:
{
"validators.fileType.unsupported": "Il tipo di file '{0}' non è supportato. Solo i file CSS e JavaScript possono essere minimizzati.",
"validators.content.empty": "Impossibile minimizzare un file {0} vuoto. Aggiungi prima del contenuto.",
"fileService.newFile.success": "File minimizzato con successo e salvato come: {0}",
"fileService.inPlace.success": "{0} è stato minimizzato con successo.",
"minificationService.fileType.unsupported": "Tipo di file non supportato per la minimizzazione: {0}",
"minificationService.fileSize.tooLarge": "File troppo grande: {0}MB. La dimensione massima consentita è 5MB. Riduci la dimensione del file e riprova.",
"minificationService.error.missingInput": "Parametro di input mancante. Assicurati che il file abbia del contenuto.",
"minificationService.error.invalidMethod": "Metodo di richiesta non valido. Questo è un errore interno, riprova.",
"minificationService.error.invalidContentType": "Tipo di contenuto non valido. Questo è un errore interno, riprova.",
"minificationService.error.fileTooLarge": "File troppo grande. La dimensione massima consentita è 5MB. Riduci la dimensione del file.",
"minificationService.error.invalidSyntax": "Sintassi {0} non valida. Controlla il codice per errori di sintassi.",
"minificationService.error.rateLimitExceeded": "Troppe richieste. Il limite API è 30 richieste al minuto. Attendi e riprova.",
"minificationService.error.apiError": "Errore API {0} ({1}): {2}",
"minificationService.error.invalidResponse": "Formato di risposta non valido dall'API di minimizzazione",
"minificationService.error.timeout": "Timeout di minimizzazione: Il servizio {0} sta impiegando più tempo del previsto. Controlla la connessione Internet e riprova.",
"minificationService.error.network": "Errore di rete: Impossibile connettersi al servizio di minimizzazione. Controlla la connessione Internet e riprova.",
"minificationService.error.generic": "Impossibile minimizzare il file {0}: {1}"
}Critical Requirements:
- Must have exactly 17 keys
- Preserve all placeholders:
{0},{1},{2}in correct positions - Maintain professional tone suitable for error messages
- Keep technical terms (CSS, JavaScript, API, MB) untranslated
Edit src/test/i18n.test.ts to include the new language:
const SUPPORTED_LANGUAGES = [
{ code: 'en', name: 'English', file: 'package.nls.json' },
{ code: 'es', name: 'Spanish', file: 'package.nls.es.json' },
{ code: 'fr', name: 'French', file: 'package.nls.fr.json' },
{ code: 'de', name: 'German', file: 'package.nls.de.json' },
{ code: 'pt-br', name: 'Brazilian Portuguese', file: 'package.nls.pt-br.json' },
{ code: 'ja', name: 'Japanese', file: 'package.nls.ja.json' },
{ code: 'zh-cn', name: 'Chinese Simplified', file: 'package.nls.zh-cn.json' },
{ code: 'it', name: 'Italian', file: 'package.nls.it.json' } // New language
];
const RUNTIME_BUNDLES = [
{ code: 'en', name: 'English', file: 'bundle.l10n.json' },
{ code: 'es', name: 'Spanish', file: 'bundle.l10n.es.json' },
{ code: 'fr', name: 'French', file: 'bundle.l10n.fr.json' },
{ code: 'de', name: 'German', file: 'bundle.l10n.de.json' },
{ code: 'pt-br', name: 'Brazilian Portuguese', file: 'bundle.l10n.pt-br.json' },
{ code: 'ja', name: 'Japanese', file: 'bundle.l10n.ja.json' },
{ code: 'zh-cn', name: 'Chinese Simplified', file: 'bundle.l10n.zh-cn.json' },
{ code: 'it', name: 'Italian', file: 'bundle.l10n.it.json' } // New language
];Run comprehensive validation:
# 1. Verify JSON syntax
jq empty package.nls.it.json
jq empty l10n/bundle.l10n.it.json
# 2. Count keys (should be 13 and 17)
echo "Package keys: $(jq 'keys | length' package.nls.it.json)"
echo "Runtime keys: $(jq 'keys | length' l10n/bundle.l10n.it.json)"
# 3. Compare keys with English (should have no differences)
diff <(jq -r 'keys[]' package.nls.json | sort) \
<(jq -r 'keys[]' package.nls.it.json | sort)
diff <(jq -r 'keys[]' l10n/bundle.l10n.json | sort) \
<(jq -r 'keys[]' l10n/bundle.l10n.it.json | sort)
# 4. Verify placeholder preservation
grep -E '\{[0-9]\}' l10n/bundle.l10n.it.json# Compile tests
npm run compile-tests
# Run i18n tests
npx vscode-test --grep "Internationalization"Expected Results:
- ✅ All language files exist
- ✅ All language files are valid JSON
- ✅ All language files have the same keys
- ✅ All expected keys exist
- ✅ All values are non-empty strings
- ✅ Placeholders are preserved
-
Install Italian Language Pack:
- Open Command Palette (Ctrl/Cmd+Shift+P)
- Type "Configure Display Language"
- Select "Install additional languages"
- Install "Italian Language Pack"
-
Change VS Code Language:
- Command Palette → "Configure Display Language"
- Select "Italiano (Italian)"
- Restart VS Code
-
Test Extension:
- Open a CSS or JS file
- Try minifying (should see Italian messages)
- Try with invalid file type (should see Italian error)
- Check settings (should see Italian descriptions)
Update the language support table in:
README.md- Add Italian flag and namedocs/INTERNATIONALIZATION.md- Add to supported languages table.github/copilot-instructions.md- Add to language list
### Added
- 🇮🇹 Italian (it) language support
- Complete package.nls.it.json with 13 translations
- Complete l10n/bundle.l10n.it.json with 17 runtime messages| Language | Code | Locale | Users |
|---|---|---|---|
| Italian | it | it | ~2M developers |
| Korean | ko | ko | ~3M developers |
| Russian | ru | ru | ~5M developers |
| Polish | pl | pl | ~500K developers |
| Dutch | nl | nl | ~500K developers |
| Turkish | tr | tr | ~500K developers |
Professional Translation Services:
- Crowdin (https://crowdin.com/)
- Lokalise (https://lokalise.com/)
- POEditor (https://poeditor.com/)
Terminology Databases:
- Microsoft Terminology: https://www.microsoft.com/en-us/language
- Apple Style Guide: https://help.apple.com/applestyleguide/
- Google Developer Documentation Style Guide
Community Translation:
- Request translations in GitHub issues
- Accept pull requests from native speakers
- Use VS Code's built-in language packs as reference
- Preserve Placeholders: Always keep {0}, {1}, etc. in the same order
- Context Awareness: Understand the context where the message appears
- Consistent Terminology: Use consistent terms for "minify", "file", "error", etc.
- Character Limits: Consider UI space constraints for menu items
- Professional Tone: Maintain a professional, helpful tone in error messages
- Always Use l10n.t(): Never hardcode user-facing strings
- Descriptive Keys: Use clear, hierarchical key names
- Document Parameters: Comment what each placeholder represents
- Test All Languages: Verify translations load correctly
- Update All Files: When adding keys, update all language files
VS Code automatically selects the appropriate language based on:
- User's VS Code display language setting (
locale) - System locale if VS Code language not explicitly set
- Falls back to English if no matching translation exists
Users can change their VS Code language:
- Open Command Palette (Ctrl/Cmd+Shift+P)
- Type "Configure Display Language"
- Select desired language
- Restart VS Code
- Translation files are loaded once at extension activation
- No runtime performance impact from l10n.t() calls
- Bundles are small (~2KB per language)
- VS Code caches translations efficiently
- Add key to English files first (
package.nls.jsonandl10n/bundle.l10n.json) - Update all other language files with translations
- Run i18n tests to verify consistency
- Update this documentation if adding new categories
- Review translations when updating VS Code API messages
- Monitor user feedback for translation quality issues
- Consider professional translation services for new languages
When updating or modifying existing translations:
# Compare translation keys between versions
git diff v1.0.0..HEAD -- package.nls.json l10n/bundle.l10n.jsonFor each changed key:
- Update English translation first as the reference
- Update all other language files (es, fr, de, pt-br, ja, zh-cn)
- Preserve parameter placeholders ({0}, {1}, etc.)
- Maintain consistent terminology
# Run i18n test suite
npm run compile-tests
npx vscode-test --grep "Internationalization"
# Verify all languages have same keys
for file in package.nls*.json; do
echo "$file: $(cat $file | jq 'keys | length')"
done- Change VS Code display language to each supported language
- Test all commands and error scenarios
- Verify messages display correctly with proper formatting
- Check that parameter interpolation works
Before (v1.0.0):
// l10n/bundle.l10n.json
{
"validators.fileType.unsupported": "File type '{0}' is not supported."
}After (v1.1.0):
// l10n/bundle.l10n.json
{
"validators.fileType.unsupported": "File type '{0}' is not supported. Only CSS and JavaScript files can be minified."
}Migration checklist:
- Update English bundle.l10n.json
- Update all 6 other language bundles
- Run i18n tests
- Test with each language in VS Code
Symptom: Extension shows English messages even though VS Code is set to another language.
Possible Causes:
-
Missing Translation File
# Verify all translation files exist ls -1 package.nls*.json l10n/bundle.l10n*.json
-
Invalid JSON in Translation File
# Validate JSON syntax for each language for file in package.nls*.json l10n/bundle.l10n*.json; do echo "Checking $file..." jq empty "$file" 2>&1 || echo "ERROR in $file" done
-
VS Code Language Pack Not Installed
- Open Command Palette (Ctrl/Cmd+Shift+P)
- Type "Configure Display Language"
- Install the language pack if prompted
- Restart VS Code
-
Locale Code Mismatch
- VS Code uses specific locale codes (e.g.,
pt-br, notpt) - Check VS Code's locale: Help → About → Copy locale info
- Ensure translation file matches exact locale code
- VS Code uses specific locale codes (e.g.,
Solution:
# Run i18n test suite to identify issues
npm run compile-tests
npx vscode-test --grep "Internationalization"Symptom: Extension crashes or shows [Missing translation] errors.
Possible Causes:
-
Key Mismatch Between Files
# Compare keys across all languages diff <(jq -r 'keys[]' package.nls.json | sort) \ <(jq -r 'keys[]' package.nls.es.json | sort)
-
Typo in l10n.t() Call
// Wrong l10n.t('validators.fileType.unsupported') // Correct (must match key in bundle.l10n.json) l10n.t('validators.fileType.unsupported', fileType)
Solution:
- Run i18n tests to verify key consistency
- Check for typos in source code l10n.t() calls
- Ensure all translation files have identical keys
Symptom: Messages show {0} or {1} instead of actual values.
Possible Causes:
-
Missing Parameters in l10n.t() Call
// Wrong - missing parameter l10n.t('validators.fileType.unsupported') // Correct - includes parameter l10n.t('validators.fileType.unsupported', fileType)
-
Parameter Order Mismatch
// Translation: "File {0} is too large: {1}MB" // Wrong - reversed parameters l10n.t('error.fileTooLarge', sizeMB, fileName) // Correct - matches placeholder order l10n.t('error.fileTooLarge', fileName, sizeMB)
Solution:
- Always pass required parameters to l10n.t()
- Ensure parameter order matches placeholders in translation
- Test with actual values, not just in development
Symptom: Extension fails to activate or VS Code shows error.
Possible Causes:
-
Syntax Error in JSON Files
- Missing commas between entries
- Unescaped quotes in translations
- Trailing commas in JSON
-
Invalid UTF-8 Encoding
- Ensure all translation files use UTF-8 encoding
- Special characters must be properly encoded
Solution:
# Validate all JSON files
npm run lint
# Check file encoding
file -i package.nls*.json l10n/bundle.l10n*.json
# Re-compile and test
npm run compile
npm run pretestSymptom: Translations are technically correct but sound unnatural or confusing.
Common Issues:
- Literal Translation: Translated word-by-word without considering context
- Missing Cultural Context: Technical terms that don't translate directly
- Inconsistent Terminology: Same concept translated differently across messages
Best Practices:
- Use professional translators familiar with technical content
- Maintain a glossary of technical terms for consistency
- Have native speakers review translations for natural phrasing
- Consider regional differences (e.g., European vs. Latin American Spanish)
Resources for Quality Translations:
- Microsoft Terminology Database
- Apple Localization Guidelines
- Google Developer Style Guides
Symptom: Extension works in development but not after packaging.
Possible Causes:
- Translation files not included in webpack config
.vscodeignoreexcluding translation files
Solution:
// webpack.config.cjs - ensure l10n is included
module.exports = {
// ...
resolve: {
extensions: ['.ts', '.js', '.json']
}
};Verify .vscodeignore doesn't exclude translation files:
# Check what will be packaged
vsce lsSymptom: Extension activation is slower after adding translations.
Analysis:
- Translation files are loaded once at activation
- Each bundle is ~2KB, total ~14KB for all languages
- This should have negligible impact (<50ms)
If Performance Degrades:
-
Check Bundle Sizes
du -h l10n/*.json package.nls*.json
-
Profile Extension Loading
- Open Developer Tools: Help → Toggle Developer Tools
- Go to Performance tab
- Record extension activation
- Look for l10n-related bottlenecks
-
Verify Webpack Configuration
# Check bundle size npm run package ls -lh *.vsix
Solution:
- Ensure webpack is properly minifying translations
- Verify l10n package is using VS Code's cached translations
- Consider lazy loading for rare languages (advanced)
| Error | Cause | Solution |
|---|---|---|
Cannot find module '@vscode/l10n' |
Package not installed | Run npm install |
l10n.t is not a function |
Missing import statement | Add import * as l10n from '@vscode/l10n'; |
Translation key not found |
Key doesn't exist in bundle | Check key spelling and bundle file |
Unexpected token in JSON |
Syntax error in .nls file | Validate JSON with jq or online validator |
Encoding error |
Non-UTF-8 characters | Save files with UTF-8 encoding |
For translation issues or requests for additional languages:
- Open an issue on GitHub
- Tag with
i18nlabel - Provide language code and any specific translation concerns