pub struct Codec {
    pub resources: Vec<Resource>,
}Expand description
Represents a collection of localized resources and provides methods to read, write, cache, and load these resources.
Fields§
§resources: Vec<Resource>The collection of resources managed by this codec.
Implementations§
Source§impl Codec
 
impl Codec
Sourcepub fn builder() -> CodecBuilder
 
pub fn builder() -> CodecBuilder
Creates a new CodecBuilder for fluent construction.
This method returns a builder that allows you to chain method calls
to add resources from files and then build the final Codec instance.
§Example
use langcodec::Codec;
let codec = Codec::builder()
    .add_file("en.strings")?
    .add_file("fr.strings")?
    .build();§Returns
Returns a new CodecBuilder instance.
Sourcepub fn iter_mut(&mut self) -> IterMut<'_, Resource>
 
pub fn iter_mut(&mut self) -> IterMut<'_, Resource>
Returns a mutable iterator over all resources.
Sourcepub fn get_by_language(&self, lang: &str) -> Option<&Resource>
 
pub fn get_by_language(&self, lang: &str) -> Option<&Resource>
Finds a resource by its language code, if present.
Sourcepub fn get_mut_by_language(&mut self, lang: &str) -> Option<&mut Resource>
 
pub fn get_mut_by_language(&mut self, lang: &str) -> Option<&mut Resource>
Finds a mutable resource by its language code, if present.
Sourcepub fn add_resource(&mut self, resource: Resource)
 
pub fn add_resource(&mut self, resource: Resource)
Adds a new resource to the collection.
Sourcepub fn extend_from(&mut self, other: Codec)
 
pub fn extend_from(&mut self, other: Codec)
Appends all resources from another Codec into this one.
Sourcepub fn from_codecs<I>(codecs: I) -> Codecwhere
    I: IntoIterator<Item = Codec>,
 
pub fn from_codecs<I>(codecs: I) -> Codecwhere
    I: IntoIterator<Item = Codec>,
Constructs a Codec from multiple Codec instances by concatenating their resources.
Sourcepub fn merge_codecs<I>(codecs: I, strategy: &ConflictStrategy) -> Codecwhere
    I: IntoIterator<Item = Codec>,
 
pub fn merge_codecs<I>(codecs: I, strategy: &ConflictStrategy) -> Codecwhere
    I: IntoIterator<Item = Codec>,
Merges multiple Codec instances into one and merges resources by language using the given strategy.
Returns the merged Codec containing resources merged per language group.
Sourcepub fn find_entries(&self, key: &str) -> Vec<(&Resource, &Entry)>
 
pub fn find_entries(&self, key: &str) -> Vec<(&Resource, &Entry)>
Finds an entry by its key across all languages.
Returns an iterator over all resources and their matching entries.
§Arguments
- key- The entry key to search for
§Returns
An iterator yielding (&Resource, &Entry) pairs for all matching entries.
§Example
use langcodec::Codec;
let mut codec = Codec::new();
// ... load resources ...
for (resource, entry) in codec.find_entries("welcome_message") {
    println!("{}: {}", resource.metadata.language, entry.value);
}Sourcepub fn find_entry(&self, key: &str, language: &str) -> Option<&Entry>
 
pub fn find_entry(&self, key: &str, language: &str) -> Option<&Entry>
Finds an entry by its key in a specific language.
§Arguments
- key- The entry key to search for
- language- The language code (e.g., “en”, “fr”)
§Returns
Some(&Entry) if found, None otherwise.
§Example
use langcodec::Codec;
let mut codec = Codec::new();
// ... load resources ...
if let Some(entry) = codec.find_entry("welcome_message", "en") {
    println!("English welcome: {}", entry.value);
}Sourcepub fn find_entry_mut(
    &mut self,
    key: &str,
    language: &str,
) -> Option<&mut Entry>
 
pub fn find_entry_mut( &mut self, key: &str, language: &str, ) -> Option<&mut Entry>
Finds a mutable entry by its key in a specific language.
§Arguments
- key- The entry key to search for
- language- The language code (e.g., “en”, “fr”)
§Returns
Some(&mut Entry) if found, None otherwise.
§Example
use langcodec::Codec;
use langcodec::types::Translation;
let mut codec = Codec::new();
// ... load resources ...
if let Some(entry) = codec.find_entry_mut("welcome_message", "en") {
    entry.value = Translation::Singular("Hello, World!".to_string());
    entry.status = langcodec::types::EntryStatus::Translated;
}Sourcepub fn update_translation(
    &mut self,
    key: &str,
    language: &str,
    translation: Translation,
    status: Option<EntryStatus>,
) -> Result<(), Error>
 
pub fn update_translation( &mut self, key: &str, language: &str, translation: Translation, status: Option<EntryStatus>, ) -> Result<(), Error>
Updates a translation for a specific key and language.
§Arguments
- key- The entry key to update
- language- The language code (e.g., “en”, “fr”)
- translation- The new translation value
- status- Optional new status (defaults to- Translated)
§Returns
Ok(()) if the entry was found and updated, Err if not found.
§Example
use langcodec::{Codec, types::{Translation, EntryStatus}};
let mut codec = Codec::new();
// Add an entry first
codec.add_entry("welcome", "en", Translation::Singular("Hello".to_string()), None, None)?;
codec.update_translation(
    "welcome",
    "en",
    Translation::Singular("Hello, World!".to_string()),
    Some(EntryStatus::Translated)
)?;Sourcepub fn add_entry(
    &mut self,
    key: &str,
    language: &str,
    translation: Translation,
    comment: Option<String>,
    status: Option<EntryStatus>,
) -> Result<(), Error>
 
pub fn add_entry( &mut self, key: &str, language: &str, translation: Translation, comment: Option<String>, status: Option<EntryStatus>, ) -> Result<(), Error>
Adds a new entry to a specific language.
If the language doesn’t exist, it will be created automatically.
§Arguments
- key- The entry key
- language- The language code (e.g., “en”, “fr”)
- translation- The translation value
- comment- Optional comment for translators
- status- Optional status (defaults to- New)
§Returns
Ok(()) if the entry was added successfully.
§Example
use langcodec::{Codec, types::{Translation, EntryStatus}};
let mut codec = Codec::new();
codec.add_entry(
    "new_message",
    "en",
    Translation::Singular("This is a new message".to_string()),
    Some("This is a new message for users".to_string()),
    Some(EntryStatus::New)
)?;Sourcepub fn remove_entry(&mut self, key: &str, language: &str) -> Result<(), Error>
 
pub fn remove_entry(&mut self, key: &str, language: &str) -> Result<(), Error>
Removes an entry from a specific language.
§Arguments
- key- The entry key to remove
- language- The language code (e.g., “en”, “fr”)
§Returns
Ok(()) if the entry was found and removed, Err if not found.
§Example
use langcodec::{Codec, types::{Translation, EntryStatus}};
let mut codec = Codec::new();
// Add a resource first
codec.add_entry("test_key", "en", Translation::Singular("Test".to_string()), None, None)?;
// Now remove it
codec.remove_entry("test_key", "en")?;Sourcepub fn copy_entry(
    &mut self,
    key: &str,
    from_language: &str,
    to_language: &str,
    update_status: bool,
) -> Result<(), Error>
 
pub fn copy_entry( &mut self, key: &str, from_language: &str, to_language: &str, update_status: bool, ) -> Result<(), Error>
Copies an entry from one language to another.
This is useful for creating new translations based on existing ones.
§Arguments
- key- The entry key to copy
- from_language- The source language
- to_language- The target language
- update_status- Whether to update the status to- Newin the target language
§Returns
Ok(()) if the entry was copied successfully, Err if not found.
§Example
use langcodec::{Codec, types::{Translation, EntryStatus}};
let mut codec = Codec::new();
// Add source entry first
codec.add_entry("welcome", "en", Translation::Singular("Hello".to_string()), None, None)?;
// Copy English entry to French as a starting point
codec.copy_entry("welcome", "en", "fr", true)?;Sourcepub fn has_entry(&self, key: &str, language: &str) -> bool
 
pub fn has_entry(&self, key: &str, language: &str) -> bool
Checks if an entry exists in a specific language.
§Arguments
- key- The entry key to check
- language- The language code (e.g., “en”, “fr”)
§Returns
true if the entry exists, false otherwise.
§Example
use langcodec::Codec;
let codec = Codec::new();
// ... load resources ...
if codec.has_entry("welcome_message", "en") {
    println!("English welcome message exists");
}Sourcepub fn entry_count(&self, language: &str) -> usize
 
pub fn entry_count(&self, language: &str) -> usize
Gets the count of entries in a specific language.
§Arguments
- language- The language code (e.g., “en”, “fr”)
§Returns
The number of entries in the specified language, or 0 if the language doesn’t exist.
§Example
use langcodec::Codec;
let codec = Codec::new();
// ... load resources ...
let count = codec.entry_count("en");
println!("English has {} entries", count);Sourcepub fn validate(&self) -> Result<(), Error>
 
pub fn validate(&self) -> Result<(), Error>
Validates the codec for common issues.
§Returns
Ok(()) if validation passes, Err(Error) with details if validation fails.
§Example
use langcodec::Codec;
let mut codec = Codec::new();
// ... add resources ...
if let Err(validation_error) = codec.validate() {
    eprintln!("Validation failed: {}", validation_error);
}Sourcepub fn validate_plurals(&self) -> Result<(), Error>
 
pub fn validate_plurals(&self) -> Result<(), Error>
Validates plural completeness per CLDR category sets for each locale.
For each plural entry in each resource, checks that all required plural categories for the language are present. Returns a Validation error with aggregated details if any are missing.
Sourcepub fn collect_plural_issues(&self) -> Vec<PluralValidationReport>
 
pub fn collect_plural_issues(&self) -> Vec<PluralValidationReport>
Collects non-fatal plural validation reports across all resources.
Sourcepub fn autofix_fill_missing_from_other(&mut self) -> usize
 
pub fn autofix_fill_missing_from_other(&mut self) -> usize
Autofix: fill missing plural categories using ‘other’ and mark entries as NeedsReview. Returns total categories added across all resources.
Sourcepub fn clean_up_resources(&mut self)
 
pub fn clean_up_resources(&mut self)
Cleans up resources by removing empty resources and entries.
Sourcepub fn validate_placeholders(&self, strict: bool) -> Result<(), Error>
 
pub fn validate_placeholders(&self, strict: bool) -> Result<(), Error>
Validate placeholder consistency across languages for each key.
Rules (initial version):
- For each key, each language must have the same placeholder signature.
- For plural entries, all forms within a language must share the same signature.
- iOS vs Android differences like %@/%1$@vs%s/%1$sare normalized.
Example
use langcodec::{Codec, types::{Entry, EntryStatus, Metadata, Resource, Translation}};
let mut codec = Codec::new();
let en = Resource{
    metadata: Metadata{ language: "en".into(), domain: String::new(), custom: Default::default() },
    entries: vec![Entry{ id: "greet".into(), value: Translation::Singular("Hello %1$@".into()), comment: None, status: EntryStatus::Translated, custom: Default::default() }]
};
let fr = Resource{
    metadata: Metadata{ language: "fr".into(), domain: String::new(), custom: Default::default() },
    entries: vec![Entry{ id: "greet".into(), value: Translation::Singular("Bonjour %1$s".into()), comment: None, status: EntryStatus::Translated, custom: Default::default() }]
};
codec.add_resource(en);
codec.add_resource(fr);
assert!(codec.validate_placeholders(true).is_ok());Sourcepub fn collect_placeholder_issues(&self) -> Vec<String>
 
pub fn collect_placeholder_issues(&self) -> Vec<String>
Collect placeholder issues without failing. Returns a list of human-readable messages; empty if none.
Useful to warn in non-strict mode.
Sourcepub fn normalize_placeholders_in_place(&mut self)
 
pub fn normalize_placeholders_in_place(&mut self)
Normalize placeholders in all entries (mutates in place).
Converts iOS patterns like %@, %1$@, %ld to canonical forms (%s, %1$s, %d/%u).
Example
use langcodec::{Codec, types::{Entry, EntryStatus, Metadata, Resource, Translation}};
let mut codec = Codec::new();
codec.add_resource(Resource{
    metadata: Metadata{ language: "en".into(), domain: String::new(), custom: Default::default() },
    entries: vec![Entry{ id: "id".into(), value: Translation::Singular("Hello %@ and %1$@".into()), comment: None, status: EntryStatus::Translated, custom: Default::default() }]
});
codec.normalize_placeholders_in_place();
let v = match &codec.resources[0].entries[0].value { Translation::Singular(v) => v.clone(), _ => unreachable!() };
assert!(v.contains("%s") && v.contains("%1$s"));Sourcepub fn merge_resources(&mut self, strategy: &ConflictStrategy) -> usize
 
pub fn merge_resources(&mut self, strategy: &ConflictStrategy) -> usize
Merge resources with the same language by the given strategy.
This method groups resources by language and merges multiple resources that share the same language into a single resource. Resources with unique languages are left unchanged.
§Arguments
- strategy- The conflict resolution strategy to use when merging entries with the same ID across multiple resources
§Returns
The number of merge operations performed. A merge operation occurs when there are 2 or more resources for the same language.
§Example
use langcodec::{Codec, types::ConflictStrategy};
let mut codec = Codec::new();
// ... add resources with same language ...
let merges_performed = codec.merge_resources(&ConflictStrategy::Last);
println!("Merged {} language groups", merges_performed);§Behavior
- Resources are grouped by language
- Only languages with multiple resources are merged
- The merged resource replaces all original resources for that language
- Resources with unique languages remain unchanged
- Entries are merged according to the specified conflict strategy
Sourcepub fn write_resource_to_file(
    resource: &Resource,
    output_path: &str,
) -> Result<(), Error>
 
pub fn write_resource_to_file( resource: &Resource, output_path: &str, ) -> Result<(), Error>
Writes a resource to a file with automatic format detection.
§Arguments
- resource- The resource to write
- output_path- The output file path
§Returns
Ok(()) on success, Err(Error) on failure.
§Example
use langcodec::{Codec, types::{Resource, Metadata, Entry, Translation, EntryStatus}};
let resource = Resource {
    metadata: Metadata {
        language: "en".to_string(),
        domain: "domain".to_string(),
        custom: std::collections::HashMap::new(),
    },
    entries: vec![],
};
Codec::write_resource_to_file(&resource, "output.strings")?;Sourcepub fn read_file_by_type<P>(
    &mut self,
    path: P,
    format_type: FormatType,
) -> Result<(), Error>
 
pub fn read_file_by_type<P>( &mut self, path: P, format_type: FormatType, ) -> Result<(), Error>
Sourcepub fn read_file_by_extension<P>(
    &mut self,
    path: P,
    lang: Option<String>,
) -> Result<(), Error>
 
pub fn read_file_by_extension<P>( &mut self, path: P, lang: Option<String>, ) -> Result<(), Error>
Reads a resource file by inferring its format from the file extension. Optionally infers language from the path if not provided.
§Parameters
- path: Path to the resource file.
- lang: Optional language code to use.
§Returns
Ok(()) if the file was successfully read,
or an Error if the format is unsupported or reading fails.
Sourcepub fn write_to_file(&self) -> Result<(), Error>
 
pub fn write_to_file(&self) -> Result<(), Error>
Writes all managed resources back to their respective files, grouped by domain.
§Returns
Ok(()) if all writes succeed, or an Error otherwise.
Sourcepub fn cache_to_file<P>(&self, path: P) -> Result<(), Error>
 
pub fn cache_to_file<P>(&self, path: P) -> Result<(), Error>
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Codec
impl RefUnwindSafe for Codec
impl Send for Codec
impl Sync for Codec
impl Unpin for Codec
impl UnwindSafe for Codec
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
    T: ?Sized,
 
impl<T> BorrowMut<T> for Twhere
    T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
 
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
    T: Clone,
 
impl<T> CloneToUninit for Twhere
    T: Clone,
Source§impl<T> IntoEither for T
 
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
 
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
 
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more