extract path logic

This commit is contained in:
Marcel Märtens 2021-07-29 11:29:15 +02:00
parent bdda5ccd72
commit c3aa4c54a9
7 changed files with 233 additions and 269 deletions

View File

@ -2,7 +2,7 @@ use crate::{
gitfragments::{
read_file_from_path, transform_fragment, LocalizationEntryState, LocalizationState,
},
i18n_directories,
path::{BasePath, LangPath},
raw::{self, RawFragment, RawLanguage},
stats::{
print_csv_file, print_overall_stats, print_translation_stats, LocalizationAnalysis,
@ -10,45 +10,35 @@ use crate::{
},
REFERENCE_LANG,
};
use hashbrown::{hash_map::Entry, HashMap, HashSet};
use hashbrown::{hash_map::Entry, HashMap};
use ron::de::from_bytes;
use std::path::Path;
/// Fill the entry State base information (except `state`) for a complete
/// language
fn gather_entry_state<'a>(
repo: &'a git2::Repository,
head_ref: &git2::Reference,
language_identifier: &str,
root_path: &Path,
relative_i18n_root_path: &Path,
path: &LangPath,
) -> RawLanguage<LocalizationEntryState> {
println!("-> {:?}", &language_identifier);
let i18n_root_path = root_path.join(relative_i18n_root_path);
println!("-> {:?}", path.language_identifier());
// load standard manifest
let manifest = raw::load_manifest(&i18n_root_path, language_identifier)
.expect("failed to load language manifest");
let manifest = raw::load_manifest(path).expect("failed to load language manifest");
// transform language into LocalizationEntryState
let mut fragments = HashMap::new();
// For each file in directory
let files = raw::fragments_pathes_in_language(&i18n_root_path, language_identifier)
let files = path
.fragments()
.expect("failed to get all files in language");
for subpath in files {
let path = relative_i18n_root_path
.join(language_identifier)
.join(&subpath);
println!(" -> {:?}", &subpath);
let i18n_blob = read_file_from_path(repo, head_ref, &path);
let fragment: RawFragment<String> = from_bytes(i18n_blob.content()).unwrap_or_else(|e| {
panic!(
"Could not parse {} RON file, skipping: {}",
subpath.to_string_lossy(),
e
)
});
let frag = transform_fragment(repo, (&path, fragment), &i18n_blob);
fragments.insert(subpath.to_path_buf(), frag);
for sub_path in files {
let fullpath = path.sub_path(&sub_path);
let gitpath = fullpath.strip_prefix(path.base().root_path()).unwrap();
println!(" -> {:?}", &sub_path);
let i18n_blob = read_file_from_path(repo, head_ref, gitpath);
let fragment: RawFragment<String> = from_bytes(i18n_blob.content())
.unwrap_or_else(|e| panic!("Could not parse {:?} RON file, error: {}", sub_path, e));
let frag = transform_fragment(repo, (gitpath, fragment), &i18n_blob);
fragments.insert(sub_path, frag);
}
RawLanguage::<LocalizationEntryState> {
@ -138,11 +128,10 @@ fn compare_lang_with_reference(
}
}
let ref_keys: HashSet<&String> = ref_fragment.string_map.keys().collect();
for (_, state) in cur_fragment
.string_map
.iter_mut()
.filter(|&(k, _)| !ref_keys.contains(k))
.filter(|&(k, _)| ref_fragment.string_map.get(k).is_none())
{
state.state = Some(LocalizationState::Unused);
}
@ -179,67 +168,42 @@ fn gather_results(
(state_map, stats)
}
/// completely analysis multiple languages without printing
fn complete_analysis(
language_identifiers: &[&str],
root_path: &Path,
relative_i18n_root_path: &Path,
) -> (
HashMap<String, (LocalizationAnalysis, LocalizationStats)>,
/* ref lang */ RawLanguage<LocalizationEntryState>,
) {
let mut result = HashMap::new();
// Initialize Git objects
let repo = git2::Repository::discover(&root_path)
.unwrap_or_else(|_| panic!("Failed to open the Git repository at {:?}", &root_path));
let head_ref = repo.head().expect("Impossible to get the HEAD reference");
// Read Reference Language
let ref_language = gather_entry_state(
&repo,
&head_ref,
REFERENCE_LANG,
root_path,
relative_i18n_root_path,
);
for &language_identifier in language_identifiers {
let mut cur_language = gather_entry_state(
&repo,
&head_ref,
language_identifier,
root_path,
relative_i18n_root_path,
);
compare_lang_with_reference(&mut cur_language, &ref_language, &repo);
let (state_map, stats) = gather_results(&cur_language);
result.insert(language_identifier.to_owned(), (state_map, stats));
}
(result, ref_language)
}
/// Test one language
/// - `code`: name of the directory in assets (de_DE for example)
/// - `root_path`: absolute path to main repo
/// - `relative_i18n_root_path`: relative path to asset directory (right now it
/// is 'assets/voxygen/i18n')
/// - be_verbose: print extra info
/// - csv_enabled: generate csv files in target folder
/// - `path`: path to repo
/// - `be_verbose`: print extra info
/// - `csv_enabled`: generate csv files in target folder
pub fn test_specific_localizations(
path: &BasePath,
language_identifiers: &[&str],
root_path: &Path,
relative_i18n_root_path: &Path,
be_verbose: bool,
csv_enabled: bool,
) {
let (analysis, reference_language) =
complete_analysis(language_identifiers, root_path, relative_i18n_root_path);
//complete analysis
let mut analysis = HashMap::new();
// Initialize Git objects
let repo = git2::Repository::discover(path.root_path())
.unwrap_or_else(|_| panic!("Failed to open the Git repository {:?}", path.root_path()));
let head_ref = repo.head().expect("Impossible to get the HEAD reference");
// Read Reference Language
let ref_language = gather_entry_state(&repo, &head_ref, &path.i18n_path(REFERENCE_LANG));
for &language_identifier in language_identifiers {
let mut cur_language =
gather_entry_state(&repo, &head_ref, &path.i18n_path(language_identifier));
compare_lang_with_reference(&mut cur_language, &ref_language, &repo);
let (state_map, stats) = gather_results(&cur_language);
analysis.insert(language_identifier.to_owned(), (state_map, stats));
}
//printing
for (language_identifier, (state_map, stats)) in &analysis {
if csv_enabled {
print_csv_file(state_map);
} else {
print_translation_stats(
language_identifier,
&reference_language,
&ref_language,
stats,
state_map,
be_verbose,
@ -252,32 +216,12 @@ pub fn test_specific_localizations(
}
/// Test all localizations
pub fn test_all_localizations(
root_path: &Path,
relative_i18n_root_path: &Path,
be_verbose: bool,
csv_enabled: bool,
) {
let i18n_root_path = root_path.join(relative_i18n_root_path);
pub fn test_all_localizations(path: &BasePath, be_verbose: bool, csv_enabled: bool) {
// Compare to other reference files
let language_identifiers = i18n_directories(&i18n_root_path)
.into_iter()
.map(|p| {
p.strip_prefix(&i18n_root_path)
.unwrap()
.to_str()
.unwrap()
.to_owned()
})
let languages = path.i18n_directories();
let language_identifiers = languages
.iter()
.map(|s| s.language_identifier())
.collect::<Vec<_>>();
test_specific_localizations(
&language_identifiers
.iter()
.map(|s| s.as_str())
.collect::<Vec<_>>(),
root_path,
relative_i18n_root_path,
be_verbose,
csv_enabled,
);
test_specific_localizations(path, &language_identifiers, be_verbose, csv_enabled);
}

View File

@ -1,5 +1,4 @@
use clap::{App, Arg};
use std::path::Path;
use veloren_i18n::{analysis, verification};
fn main() {
@ -37,28 +36,17 @@ fn main() {
// Generate paths
let root_path = common_assets::find_root().expect("Failed to find root of repository");
let relative_i18n_root_path = Path::new("assets/voxygen/i18n/");
let path = veloren_i18n::BasePath::new(&root_path);
let be_verbose = matches.is_present("verbose");
let csv_enabled = matches.is_present("csv");
if let Some(code) = matches.value_of("CODE") {
analysis::test_specific_localizations(
&[code],
&root_path,
relative_i18n_root_path,
be_verbose,
csv_enabled,
);
analysis::test_specific_localizations(&path, &[code], be_verbose, csv_enabled);
}
if matches.is_present("test") {
analysis::test_all_localizations(
&root_path,
relative_i18n_root_path,
be_verbose,
csv_enabled,
);
analysis::test_all_localizations(&path, be_verbose, csv_enabled);
}
if matches.is_present("verify") {
verification::verify_all_localizations(&root_path, relative_i18n_root_path);
verification::verify_all_localizations(&path);
}
}

View File

@ -1,29 +1,27 @@
#[cfg(any(feature = "bin", test))]
pub mod analysis;
#[cfg(any(feature = "bin", test))]
pub mod gitfragments;
pub mod raw;
mod gitfragments;
mod path;
mod raw;
#[cfg(any(feature = "bin", test))] pub mod stats;
pub mod verification;
//reexport
pub use path::BasePath;
use crate::path::{LANG_EXTENSION, LANG_MANIFEST_FILE};
use common_assets::{self, source::DirEntry, AssetExt, AssetGuard, AssetHandle};
use hashbrown::{HashMap, HashSet};
use raw::{RawFragment, RawLanguage, RawManifest};
use serde::{Deserialize, Serialize};
use std::{
fs, io,
path::{Path, PathBuf},
};
use std::{io, path::PathBuf};
use tracing::warn;
/// The reference language, aka the more up-to-date localization data.
/// Also the default language at first startup.
pub const REFERENCE_LANG: &str = "en";
pub const LANG_MANIFEST_FILE: &str = "_manifest";
pub(crate) const LANG_EXTENSION: &str = "ron";
/// How a language can be described
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct LanguageMetadata {
@ -327,18 +325,9 @@ pub fn list_localizations() -> Vec<LanguageMetadata> {
LocalizationList::load_expect_cloned("voxygen.i18n").0
}
/// List localization directories as a `PathBuf` vector
pub fn i18n_directories(i18n_dir: &Path) -> Vec<PathBuf> {
fs::read_dir(i18n_dir)
.unwrap()
.map(|res| res.map(|e| e.path()).unwrap())
.filter(|e| e.is_dir())
.collect()
}
#[cfg(test)]
mod tests {
use std::path::Path;
use crate::path::BasePath;
// Test that localization list is loaded (not empty)
#[test]
@ -358,9 +347,8 @@ mod tests {
#[test]
fn verify_all_localizations() {
// Generate paths
let i18n_root_path = Path::new("assets/voxygen/i18n/");
let root_dir = common_assets::find_root().expect("Failed to discover repository root");
crate::verification::verify_all_localizations(&root_dir, i18n_root_path);
crate::verification::verify_all_localizations(&BasePath::new(&root_dir));
}
// Test to verify all languages and print missing and faulty localisation
@ -368,8 +356,7 @@ mod tests {
#[ignore]
fn test_all_localizations() {
// Generate paths
let i18n_root_path = Path::new("assets/voxygen/i18n/");
let root_dir = common_assets::find_root().expect("Failed to discover repository root");
crate::analysis::test_all_localizations(&root_dir, i18n_root_path, true, false);
crate::analysis::test_all_localizations(&BasePath::new(&root_dir), true, false);
}
}

138
voxygen/i18n/src/path.rs Normal file
View File

@ -0,0 +1,138 @@
use std::path::{Path, PathBuf};
pub(crate) const LANG_MANIFEST_FILE: &str = "_manifest";
pub(crate) const LANG_EXTENSION: &str = "ron";
#[derive(Clone)]
pub struct BasePath {
///repo part, git main folder
root_path: PathBuf,
///relative path to i18n path which contains, currently
/// 'assets/voxygen/i18n'
relative_i18n_root_path: PathBuf,
///i18n_root_folder
cache: PathBuf,
}
impl BasePath {
pub fn new(root_path: &Path) -> Self {
let relative_i18n_root_path = Path::new("assets/voxygen/i18n").to_path_buf();
let cache = root_path.join(&relative_i18n_root_path);
assert!(
cache.is_dir(),
"i18n_root_path folder doesn't exist, something is wrong!"
);
Self {
root_path: root_path.to_path_buf(),
relative_i18n_root_path,
cache,
}
}
pub fn root_path(&self) -> &Path { &self.root_path }
pub fn relative_i18n_root_path(&self) -> &Path { &self.relative_i18n_root_path }
/// absolute path to `relative_i18n_root_path`
pub fn i18n_root_path(&self) -> &Path { &self.cache }
pub fn i18n_path(&self, language_identifier: &str) -> LangPath {
LangPath::new(self, language_identifier)
}
/// List localization directories
pub fn i18n_directories(&self) -> Vec<LangPath> {
std::fs::read_dir(&self.cache)
.unwrap()
.map(|res| res.unwrap())
.filter(|e| e.file_type().unwrap().is_dir())
.map(|e| LangPath::new(self, e.file_name().to_str().unwrap()))
.collect()
}
}
impl core::fmt::Debug for BasePath {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", &self.cache)
}
}
#[derive(Clone)]
pub struct LangPath {
base: BasePath,
/// `en`, `de_DE`, `fr_FR`, etc..
language_identifier: String,
/// i18n_path
cache: PathBuf,
}
impl LangPath {
fn new(base: &BasePath, language_identifier: &str) -> Self {
let cache = base.i18n_root_path().join(language_identifier);
if !cache.is_dir() {
panic!("language folder '{}' doesn't exist", language_identifier);
}
Self {
base: base.clone(),
language_identifier: language_identifier.to_owned(),
cache,
}
}
pub fn base(&self) -> &BasePath { &self.base }
pub fn language_identifier(&self) -> &str { &self.language_identifier }
///absolute path to `i18n_root_path` + `language_identifier`
pub fn i18n_path(&self) -> &Path { &self.cache }
/// fragment or manifest file, based on a path
pub fn sub_path(&self, sub_path: &Path) -> PathBuf { self.cache.join(sub_path) }
/// fragment or manifest file, based on a string without extension
pub fn file(&self, name_without_extension: &str) -> PathBuf {
self.cache
.join(format!("{}.{}", name_without_extension, LANG_EXTENSION))
}
/// return all fragments sub_pathes
pub(crate) fn fragments(&self) -> Result<Vec</* sub_path */ PathBuf>, std::io::Error> {
let mut result = vec![];
recursive_fragments_paths_in_language(self, Path::new(""), &mut result)?;
Ok(result)
}
}
//unwraps cant fail as they are in same Path
fn recursive_fragments_paths_in_language(
lpath: &LangPath,
subfolder: &Path,
result: &mut Vec<PathBuf>,
) -> Result<(), std::io::Error> {
let search_dir = lpath.sub_path(subfolder);
for fragment_file in search_dir.read_dir()?.flatten() {
let file_type = fragment_file.file_type()?;
let full_path = fragment_file.path();
let relative_path = full_path.strip_prefix(lpath.i18n_path()).unwrap();
if file_type.is_dir() {
recursive_fragments_paths_in_language(lpath, relative_path, result)?;
} else if file_type.is_file()
&& relative_path != Path::new(&format!("{}.{}", LANG_MANIFEST_FILE, LANG_EXTENSION))
{
result.push(relative_path.to_path_buf());
}
}
Ok(())
}
impl core::fmt::Debug for LangPath {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"{:?}",
self.base
.relative_i18n_root_path
.join(&self.language_identifier)
)
}
}

View File

@ -1,24 +1,13 @@
//! handle the loading of a `Language`
//! Paths:
//! - `root_path`: repo part, git main folder
//! - `language_identifier`: `en`, `de_DE`, `fr_FR`, etc..
//! - `relative_i18n_root_path`: relative path to i18n path which contains
//! `language_identifier` folders from `root_path`
//! - `i18n_root_path`: absolute path to `relative_i18n_root_path`
//! - `i18n_path`: absolute path to `i18n_root_path` + `language_identifier`
//! - `subfolder`: all folders in `i18n_path`
//!
//! wherever possible we use relative paths only. So expect 1 absolute
//! `root_path` or `i18n_root_path` to be required and all others be relative.
use crate::{Fonts, Language, LanguageMetadata, LANG_EXTENSION, LANG_MANIFEST_FILE};
use crate::{
path::{LangPath, LANG_EXTENSION, LANG_MANIFEST_FILE},
Fonts, Language, LanguageMetadata,
};
use deunicode::deunicode;
use hashbrown::hash_map::HashMap;
use ron::de::from_reader;
use serde::{Deserialize, Serialize};
use std::{
fs,
path::{Path, PathBuf},
};
use std::{fs, path::PathBuf};
/// Raw localization metadata from LANG_MANIFEST_FILE file
/// See `Language` for more info on each attributes
@ -47,42 +36,32 @@ pub(crate) enum RawError {
RonError(ron::Error),
}
/// `i18n_root_path` - absolute path to i18n path which contains `en`, `de_DE`,
/// `fr_FR` folders
pub(crate) fn load_manifest(
i18n_root_path: &Path,
language_identifier: &str,
) -> Result<RawManifest, common_assets::Error> {
let manifest_file = i18n_root_path
.join(language_identifier)
.join(format!("{}.{}", LANG_MANIFEST_FILE, LANG_EXTENSION));
tracing::debug!(?manifest_file, "manifest loaded");
pub(crate) fn load_manifest(path: &LangPath) -> Result<RawManifest, common_assets::Error> {
let manifest_file = path.file(LANG_MANIFEST_FILE);
tracing::debug!(?manifest_file, "manifest loading");
let f = fs::File::open(&manifest_file)?;
let manifest: RawManifest = from_reader(f).map_err(RawError::RonError)?;
// verify that the folder name `de_DE` matches the value inside the metadata!
assert_eq!(manifest.metadata.language_identifier, language_identifier);
assert_eq!(
manifest.metadata.language_identifier,
path.language_identifier()
);
Ok(manifest)
}
/// `i18n_root_path` - absolute path to i18n path which contains `en`, `de_DE`,
/// `fr_FR` files
pub(crate) fn load_raw_language(
i18n_root_path: &Path,
path: &LangPath,
manifest: RawManifest,
) -> Result<RawLanguage<String>, common_assets::Error> {
let language_identifier = &manifest.metadata.language_identifier;
let i18n_path = i18n_root_path.join(language_identifier);
//get List of files
let files = fragments_pathes_in_language(i18n_root_path, language_identifier)?;
let files = path.fragments()?;
// Walk through each file in the directory
let mut fragments = HashMap::new();
for fragment_file in &files {
let relative_path = fragment_file.strip_prefix(&i18n_path).unwrap();
let f = fs::File::open(fragment_file)?;
for sub_path in files {
let f = fs::File::open(path.sub_path(&sub_path))?;
let fragment = from_reader(f).map_err(RawError::RonError)?;
fragments.insert(relative_path.to_path_buf(), fragment);
fragments.insert(sub_path, fragment);
}
Ok(RawLanguage {
@ -126,51 +105,6 @@ impl From<RawLanguage<String>> for Language {
}
}
pub(crate) fn fragments_pathes_in_language(
i18n_root_path: &Path,
language_identifier: &str,
) -> Result<Vec</* relative to i18n_path */ PathBuf>, std::io::Error> {
let mut result = vec![];
recursive_fragments_paths_in_language(
i18n_root_path,
language_identifier,
Path::new(""),
&mut result,
)?;
Ok(result)
}
/// i18n_path = i18n_root_path.join(REFERENCE_LANG);
fn recursive_fragments_paths_in_language(
i18n_root_path: &Path,
language_identifier: &str,
subfolder: &Path,
result: &mut Vec<PathBuf>,
) -> Result<(), std::io::Error> {
let i18n_path = i18n_root_path.join(language_identifier);
let search_dir = i18n_path.join(subfolder);
for fragment_file in search_dir.read_dir().unwrap().flatten() {
let file_type = fragment_file.file_type()?;
if file_type.is_dir() {
let full_path = fragment_file.path();
let relative_path = full_path.strip_prefix(&i18n_path).unwrap();
recursive_fragments_paths_in_language(
i18n_root_path,
language_identifier,
relative_path,
result,
)?;
} else if file_type.is_file() {
let full_path = fragment_file.path();
let relative_path = full_path.strip_prefix(&i18n_path).unwrap();
if relative_path != Path::new(&format!("{}.{}", LANG_MANIFEST_FILE, LANG_EXTENSION)) {
result.push(relative_path.to_path_buf());
}
}
}
Ok(())
}
impl core::fmt::Display for RawError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {

View File

@ -45,7 +45,7 @@ impl LocalizationAnalysis {
fn show(
&self,
state: Option<LocalizationState>,
reference_language: &RawLanguage<LocalizationEntryState>,
ref_language: &RawLanguage<LocalizationEntryState>,
be_verbose: bool,
) {
let entries = self.data.get(&state).unwrap_or_else(|| {
@ -61,7 +61,7 @@ impl LocalizationAnalysis {
for (path, key, commit_id) in entries {
if be_verbose {
let our_commit = LocalizationAnalysis::print_commit(commit_id);
let ref_commit = reference_language
let ref_commit = ref_language
.fragments
.get(path)
.and_then(|entry| entry.string_map.get(key))
@ -102,7 +102,7 @@ impl LocalizationAnalysis {
pub(crate) fn print_translation_stats(
language_identifier: &str,
reference_language: &RawLanguage<LocalizationEntryState>,
ref_language: &RawLanguage<LocalizationEntryState>,
stats: &LocalizationStats,
state_map: &LocalizationAnalysis,
be_verbose: bool,
@ -116,9 +116,7 @@ pub(crate) fn print_translation_stats(
if be_verbose {
println!(
"\n{:60}| {:40} | {:40}",
"Key name",
language_identifier,
reference_language.manifest.metadata.language_identifier,
"Key name", language_identifier, ref_language.manifest.metadata.language_identifier,
);
} else {
println!("\nKey name");
@ -128,7 +126,7 @@ pub(crate) fn print_translation_stats(
if state == &Some(LocalizationState::UpToDate) {
continue;
}
state_map.show(*state, reference_language, be_verbose);
state_map.show(*state, ref_language, be_verbose);
}
println!(

View File

@ -1,26 +1,17 @@
use std::path::Path;
use crate::path::{BasePath, LangPath, LANG_MANIFEST_FILE};
use crate::{i18n_directories, raw, LANG_MANIFEST_FILE, REFERENCE_LANG};
use crate::{raw, REFERENCE_LANG};
/// Test to verify all languages that they are VALID and loadable, without
/// need of git just on the local assets folder
/// `root_path` - absolute path to main repo
/// `relative_i18n_root_path` - relative path to asset directory (right now it
/// is 'assets/voxygen/i18n')
pub fn verify_all_localizations(root_path: &Path, relative_i18n_root_path: &Path) {
let i18n_root_path = root_path.join(relative_i18n_root_path);
let ref_i18n_path = i18n_root_path.join(REFERENCE_LANG);
let ref_i18n_manifest_path =
ref_i18n_path.join(LANG_MANIFEST_FILE.to_string() + "." + crate::LANG_EXTENSION);
pub fn verify_all_localizations(path: &BasePath) {
let ref_i18n_path = path.i18n_path(REFERENCE_LANG);
let ref_i18n_manifest_path = ref_i18n_path.file(LANG_MANIFEST_FILE);
assert!(
root_path.join(&ref_i18n_path).is_dir(),
"Reference language folder doesn't exist, something is wrong!"
);
assert!(
root_path.join(&ref_i18n_manifest_path).is_file(),
ref_i18n_manifest_path.is_file(),
"Reference language manifest file doesn't exist, something is wrong!"
);
let i18n_directories = i18n_directories(&i18n_root_path);
let i18n_directories = path.i18n_directories();
// This simple check ONLY guarantees that an arbitrary minimum of translation
// files exists. It's just to notice unintentional deletion of all
// files, or modifying the paths. In case you want to delete all
@ -31,29 +22,13 @@ pub fn verify_all_localizations(root_path: &Path, relative_i18n_root_path: &Path
folder is empty?"
);
for i18n_directory in i18n_directories {
let display_language_identifier = i18n_directory
.strip_prefix(&root_path)
.unwrap()
.to_str()
.unwrap();
let language_identifier = i18n_directory
.strip_prefix(&i18n_root_path)
.unwrap()
.to_str()
.unwrap();
println!("verifying {:?}", display_language_identifier);
println!("verifying {:?}", i18n_directory);
// Walk through each files and try to load them
verify_localization_directory(root_path, relative_i18n_root_path, language_identifier);
verify_localization_directory(&i18n_directory);
}
}
fn verify_localization_directory(
root_path: &Path,
relative_i18n_root_path: &Path,
language_identifier: &str,
) {
let i18n_path = root_path.join(relative_i18n_root_path);
let manifest =
raw::load_manifest(&i18n_path, language_identifier).expect("error accessing manifest file");
raw::load_raw_language(&i18n_path, manifest).expect("error accessing fragment file");
fn verify_localization_directory(path: &LangPath) {
let manifest = raw::load_manifest(path).expect("error accessing manifest file");
raw::load_raw_language(path, manifest).expect("error accessing fragment file");
}