commit d1e222f732e7004bf1a92b8efc85e32b26ba6a2f
parent 0e65491ef17776df3142b37929357d609e45874e
Author: Terry Yiu <git@tyiu.xyz>
Date: Fri, 27 Jun 2025 21:11:23 -0400
Add localization documentation to notedeck DEVELOPER.md
Signed-off-by: Terry Yiu <git@tyiu.xyz>
Diffstat:
2 files changed, 215 insertions(+), 0 deletions(-)
diff --git a/README.md b/README.md
@@ -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).
diff --git a/crates/notedeck/DEVELOPER.md b/crates/notedeck/DEVELOPER.md
@@ -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