Add localization documentation to notedeck DEVELOPER.md

Signed-off-by: Terry Yiu <git@tyiu.xyz>
This commit is contained in:
Terry Yiu
2025-06-27 21:11:23 -04:00
committed by William Casarin
parent 0e65491ef1
commit d1e222f732
2 changed files with 215 additions and 0 deletions

View File

@@ -111,6 +111,8 @@ Building on notedeck dev documentation is also on the roadmap.
## 🤝 Contributing
### Developers
Contributions are welcome! Please check the developer documentation and follow these guidelines:
1. Fork the repository
@@ -119,6 +121,15 @@ Contributions are welcome! Please check the developer documentation and follow t
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
### Translators
Help us bring Notedeck to non-English speakers!
Request to join the Notedeck translations team through [Crowdin](https://crowdin.com/project/notedeck).
If you do not have a Crowdin account, sign up for one.
If you do not see your language, please request it in Crowdin.
## 🔒 Security
For security issues, please refer to our [Security Policy](./SECURITY.md).

View File

@@ -34,6 +34,11 @@ Notedeck is built around a modular architecture that separates concerns into dis
- `ColorTheme` - Theme management
- Various UI helpers
7. **Localization System**
- `LocalizationManager` - Core localization functionality
- `LocalizationContext` - Thread-safe context for sharing localization
- Fluent-based translation system
## Key Concepts
### Note Context and Actions
@@ -163,6 +168,197 @@ Notedeck provides several persistence mechanisms:
- `TimedSerializer` - For settings that need to be saved after a delay
- Various handlers for specific settings (zoom, theme, app size)
### Localization System
Notedeck includes a comprehensive internationalization system built on the [Fluent](https://projectfluent.org/) translation framework. The system is designed for performance and developer experience.
#### Architecture
The localization system consists of several key components:
1. **LocalizationManager** - Core functionality for managing locales and translations
2. **LocalizationContext** - Thread-safe context for sharing localization across the application
3. **Fluent Resources** - Translation files in `.ftl` format stored in `assets/translations/`
#### Key Features
- **Efficient Caching**: Parsed Fluent resources and formatted strings are cached for performance
- **Thread Safety**: Uses `RwLock` for safe concurrent access
- **Dynamic Locale Switching**: Change languages at runtime without restarting
- **Argument Support**: Localized strings can include dynamic arguments
- **Development Tools**: Pseudolocale support for testing UI layout
#### Using the tr! and tr_plural! Macros
The `tr!` and `tr_plural!` macros are the primary way to use localization in Notedeck code. They provide a convenient, type-safe interface for getting localized strings.
##### The tr! Macro
```rust
use notedeck::tr;
// Simple string with comment
let welcome = tr!("Welcome to Notedeck!", "Main welcome message");
let cancel = tr!("Cancel", "Button label to cancel an action");
// String with parameters
let greeting = tr!("Hello, {name}!", "Greeting message", name="Alice");
// Multiple parameters
let message = tr!(
"Welcome {name} to {app}!",
"Welcome message with app name",
name="Alice",
app="Notedeck"
);
// In UI components
ui.button(tr!("Reply to {user}", "Reply button text", user="alice@example.com"));
```
##### The tr_plural! Macro
Use tr_plural! when there can be multiple variations of the same string depending on
some numeric count.
Not all languages follow the same pluralization rules
```rust
use notedeck::tr_plural;
// Simple pluralization
let count = 5;
let message = tr_plural!(
"You have {count} note", // Singular form
"You have {count} notes", // Plural form
"Note count message", // Comment
count // Count value
);
// With additional parameters
let user = "Alice";
let message = tr_plural!(
"{user} has {count} note", // Singular
"{user} has {count} notes", // Plural
"User note count message", // Comment
count, // Count
user=user // Additional parameter
);
```
##### Key Features
- **Automatic Key Normalization**: Converts messages and comments into valid FTL keys
- **Fallback Handling**: Falls back to original message if translation not found
- **Parameter Interpolation**: Automatically handles named parameters
- **Comment Context**: Provides context for translators
##### Best Practices
1. **Always Include Comments**: Comments provide context for translators
```rust
// Good
tr!("Add", "Button label to add something")
// Bad
tr!("Add", "")
```
2. **Use Descriptive Comments**: Make comments specific and helpful
```rust
// Good
tr!("Reply", "Button to reply to a note")
// Bad
tr!("Reply", "Reply")
```
3. **Consistent Parameter Names**: Use consistent parameter names across related strings
```rust
// Consistent
tr!("Follow {user}", "Follow button", user="alice")
tr!("Unfollow {user}", "Unfollow button", user="alice")
```
4. **Always use tr_plural! for plural strings**: Not all languages follow English pluralization rules
```rust
// Good
// Each language can have more (or less) than just two pluralization forms.
// Let the translators and the localization system help you figure that out implicitly.
let message = tr_plural!(
"You have {count} note", // Singular form
"You have {count} notes", // Plural form
"Note count message", // Comment
count // Count value
);
// Bad
// Not all languages follow pluralization rules of English.
// Some languages can have more (or less) than two variations!
if count == 1 {
tr!("You have 1 note", "Note count message")
} else {
tr!("You have {count} notes", "Note count message")
}
```
#### Translation File Format
Translation files use the [Fluent](https://projectfluent.org/) format (`.ftl`).
Developers should never create their own `.ftl` files. Whenever user-facing strings are changed in code, run `python3 scripts/export_source_strings.py`. This script will generate `assets/translations/en-US/main.ftl` and `assets/translations/en-XA/main.ftl`. The format of the files look like the following:
```ftl
# Simple string
welcome_message = Welcome to Notedeck!
# String with arguments
welcome_user = Welcome {$name}!
# String with pluralization
note_count = {$count ->
[1] One note
*[other] {$count} notes
}
```
#### Adding New Languages
TODO
#### Development with Pseudolocale (en-XA)
For testing that all user-facing strings are going through the localization system and that the
UI layout renders well with different language translations, enable the pseudolocale:
```bash
NOTEDECK_PSEUDOLOCALE=1 cargo run -- --debug
```
The pseudolocale (`en-XA`) transforms English text in a way that is still readable but makes adjustments obvious enough that they are different from the original text (such as replacing English letters with accented equivalents), helping identify potential UI layout issues once it gets translated
to other languages.
Example transformations:
- "Add relay" → "[Àdd rélày]"
- "Cancel" → "[Çàñçél]"
- "Confirm" → "[Çóñfírm]"
#### Performance Considerations
- **Resource Caching**: Parsed Fluent resources are cached per locale
- **String Caching**: Simple strings (without arguments) are cached for repeated access
- **Cache Management**: Caches are automatically cleared when switching locales
- **Memory Limits**: String cache size can be limited to prevent memory growth
#### Testing Localization
The localization system includes comprehensive tests:
```bash
# Run localization tests
cargo test i18n
```
## Troubleshooting
### Common Issues
@@ -182,6 +378,12 @@ Notedeck provides several persistence mechanisms:
- Check for large image caches
- Consider reducing the number of active subscriptions
4. **Localization Issues**
- Verify translation files exist in the correct directory structure
- Check that locale codes are valid (e.g., `en-US`, `es-ES`)
- Ensure FTL files are properly formatted
- Look for missing translation keys in logs
## Contributing
When contributing to Notedeck:
@@ -190,3 +392,5 @@ When contributing to Notedeck:
2. Add tests for new functionality
3. Update documentation as needed
4. Keep performance in mind, especially for mobile targets
5. For UI changes, test with pseudolocale enabled
6. When adding new strings, ensure they are properly localized