diff --git a/.codescene/code-health-rules.json b/.codescene/code-health-rules.json new file mode 100644 index 000000000..3a717b703 --- /dev/null +++ b/.codescene/code-health-rules.json @@ -0,0 +1,15 @@ +{ + "usage": "Repo-scoped CodeScene overrides. Keep each rule_set narrowly scoped and justify it in matching_content_path_doc, so a reader can tell a deliberate exemption from an unexamined one.", + "rule_sets": [ + { + "matching_content_path": "build_l10n_audit/**", + "matching_content_path_doc": "Hand-rolled scanners over borrowed source text. These modules parse the define_keys! macro, the Fluent catalogues, and the Cargo metadata without taking a parser dependency into the build script, so their helpers necessarily take &str views into a buffer the caller owns: a line and its trimmed form, a message body, a table. Grouping those borrows into a context type would add a value that is constructed once and immediately unpacked at each call site, and taking String instead would allocate per line across 35 catalogues while breaking the borrowed returns. Each helper is private, called only from its own module, and reachable from a single entry point (parse_catalogue, extract_key_constants, parse_metadata_locales), so the parameter grouping is visible at a glance rather than spread across an API. Reassess if these parsers grow beyond one screen each or gain external callers.", + "rules": [ + { + "name": "String Heavy Function Arguments", + "weight": 0.0 + } + ] + } + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 1aa810e85..fcc185df6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,30 @@ ## Unreleased +### Added + +- Ship 33 further locale catalogues, so `--locale` now selects any of `ar`, + `cs`, `cy`, `da`, `de`, `el`, `en-GB`, `en-US`, `es-419`, `es-ES`, `fa`, `fi`, + `fr`, `gd`, `he`, `hi`, `hu`, `id`, `it`, `ja`, `ko`, `nb`, `nl`, `pl`, + `pt-BR`, `pt-PT`, `ro`, `ru`, `sv`, `th`, `tr`, `uk`, `vi`, `zh-Hans` or + `zh-Hant`, with `en-US` remaining the source and fallback locale + ([#466](https://github.com/leynos/netsuke/issues/466)) + ### Changed +- Select catalogues by exact locale tag with deliberate per-language fallback + rules, so `es-419` and `es-ES`, `pt-BR` and `pt-PT`, and `zh-Hans` and + `zh-Hant` stay distinct instead of collapsing onto one catalogue per language + ([#466](https://github.com/leynos/netsuke/issues/466)) +- Make `src/locale_catalogues.rs` the authoritative locale registry, read by + the embedded catalogues, the build-time audit, the `rerun-if-changed` + directives, packaging, and the tests; the build now fails if `Cargo.toml`'s + `ortho_config` locale metadata drifts from it + ([#466](https://github.com/leynos/netsuke/issues/466)) +- Extend the build-time localization audit to every declared locale and to + interpolation variables, so a message that drops or invents a `{ $variable }` + fails the build ([#466](https://github.com/leynos/netsuke/issues/466)) + - Route graph-view node registration through a borrow-returning `NodePathRegistry` accessor that looks paths up once on hits and clones a path only on insertion ([#465](https://github.com/leynos/netsuke/issues/465)) diff --git a/Cargo.lock b/Cargo.lock index ee1d85726..68513ce05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1432,6 +1432,7 @@ dependencies = [ "clap", "clap_mangen", "digest 0.11.3", + "fluent-bundle", "glob", "indexmap", "indicatif", diff --git a/Cargo.toml b/Cargo.toml index 87cc418b3..caa919c8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ include = [ "README.md", "LICENSE", "build.rs", - "build_l10n_audit.rs", + "build_l10n_audit/**", ] license = "ISC" readme = "README.md" @@ -22,7 +22,43 @@ categories = ["command-line-utilities", "development-tools::build-utils"] [package.metadata.ortho_config] root_type = "netsuke::cli::CliConfig" -locales = ["en-US", "es-ES"] +locales = [ + "ar", + "cs", + "cy", + "da", + "de", + "el", + "en-GB", + "en-US", + "es-419", + "es-ES", + "fa", + "fi", + "fr", + "gd", + "he", + "hi", + "hu", + "id", + "it", + "ja", + "ko", + "nb", + "nl", + "pl", + "pt-BR", + "pt-PT", + "ro", + "ru", + "sv", + "th", + "tr", + "uk", + "vi", + "zh-Hans", + "zh-Hant", +] [package.metadata.kani.flags] default-unwind = "6" @@ -172,6 +208,11 @@ strip-ansi-escapes = "0.2" toml = "0.8" serde_yaml = "0.9" proptest = "1.11.0" +# Plural-selection tests must pass numeric arguments to Fluent. `ortho_config` +# exposes `LocalizationArgs` as a map of `FluentValue`, but does not re-export +# the value type, so the tests need `fluent-bundle` directly. Constrained to +# the version `ortho_config` resolves, or the `FluentValue` types would differ. +fluent-bundle = "0.16.0" # Target-specific dev-deps [target.'cfg(unix)'.dev-dependencies] diff --git a/build.rs b/build.rs index ef9d85ca4..7b6a0a40a 100644 --- a/build.rs +++ b/build.rs @@ -49,8 +49,25 @@ mod cli_l10n; #[path = "src/host_pattern.rs"] mod host_pattern; +/// The locale registry, shared with the library crate. +/// +/// Both `localization` and the audit reach the registry through +/// `crate::locale_catalogues`, so it is declared at this crate's root under +/// that name. It is public because `localization` re-exports it, and a private +/// module cannot be re-exported from a public path. The build script itself +/// reads `SUPPORTED_LOCALES` to emit one `rerun-if-changed` directive per +/// catalogue. +#[path = "src/locale_catalogues.rs"] +pub mod locale_catalogues; + +/// Message rendering, shared with the library crate. +/// +/// Exposed as `crate::localization`, which `cli`, `cli_l10n`, and +/// `host_pattern` reach for `localization::keys` when building the clap +/// command for man-page generation. Public so its `locales` re-export stays +/// reachable at `crate::localization::locales`. #[path = "src/localization/mod.rs"] -mod localization; +pub mod localization; #[expect( dead_code, @@ -136,8 +153,16 @@ fn emit_rerun_directives() { println!("cargo:rerun-if-env-changed=TARGET"); println!("cargo:rerun-if-env-changed=PROFILE"); println!("cargo:rerun-if-changed=src/localization/keys.rs"); - println!("cargo:rerun-if-changed=locales/en-US/messages.ftl"); - println!("cargo:rerun-if-changed=locales/es-ES/messages.ftl"); + println!("cargo:rerun-if-changed=src/locale_catalogues.rs"); + println!("cargo:rerun-if-changed=Cargo.toml"); + // The locale registry owns the catalogue list, so the rerun directives are + // derived from it rather than repeated by hand. + for entry in locale_catalogues::SUPPORTED_LOCALES { + println!( + "cargo:rerun-if-changed={}", + build_l10n_audit::catalogue_path(entry.tag()).display() + ); + } } #[expect( diff --git a/build_l10n_audit.rs b/build_l10n_audit.rs deleted file mode 100644 index aa443a2b9..000000000 --- a/build_l10n_audit.rs +++ /dev/null @@ -1,393 +0,0 @@ -//! Localization audit helpers for the build script. -//! -//! Parses the `define_keys!` macro in `src/localization/keys.rs` and compares -//! the declared keys with Fluent bundles to keep localized resources aligned -//! with the codebase. - -use std::collections::BTreeSet; -use std::error::Error; -use std::fs; -use std::path::Path; - -const DEFINE_KEYS_MACRO: &str = "define_keys!"; -type KeySets = (BTreeSet, BTreeSet, BTreeSet); - -/// Represents the result of comparing declared keys against locale files. -struct AuditDifferences { - missing_en_us: Vec, - missing_es_es: Vec, - orphaned_en_us: Vec, - orphaned_es_es: Vec, -} - -impl AuditDifferences { - fn new( - declared: &BTreeSet, - en_us_keys: &BTreeSet, - es_es_keys: &BTreeSet, - ) -> Self { - Self { - missing_en_us: declared.difference(en_us_keys).cloned().collect(), - missing_es_es: declared.difference(es_es_keys).cloned().collect(), - orphaned_en_us: en_us_keys.difference(declared).cloned().collect(), - orphaned_es_es: es_es_keys.difference(declared).cloned().collect(), - } - } - - const fn has_issues(&self) -> bool { - !self.missing_en_us.is_empty() - || !self.missing_es_es.is_empty() - || !self.orphaned_en_us.is_empty() - || !self.orphaned_es_es.is_empty() - } - - fn format_error_message(&self) -> String { - build_audit_error_message( - &self.missing_en_us, - &self.missing_es_es, - &self.orphaned_en_us, - &self.orphaned_es_es, - ) - } -} - -fn load_key_sets( - keys_path: &Path, - en_path: &Path, - es_path: &Path, -) -> Result> { - let declared = extract_key_constants(keys_path)?; - let en_us_keys = extract_ftl_keys(en_path)?; - let es_es_keys = extract_ftl_keys(es_path)?; - Ok((declared, en_us_keys, es_es_keys)) -} - -fn compute_audit_differences( - declared: &BTreeSet, - en_us_keys: &BTreeSet, - es_es_keys: &BTreeSet, -) -> AuditDifferences { - AuditDifferences::new(declared, en_us_keys, es_es_keys) -} - -fn build_audit_error_message( - missing_en_us: &[String], - missing_es_es: &[String], - orphaned_en_us: &[String], - orphaned_es_es: &[String], -) -> String { - let mut message = String::from("localization key audit failed:"); - if !missing_en_us.is_empty() { - message.push_str("\n- missing in en-US: "); - message.push_str(&missing_en_us.join(", ")); - } - if !missing_es_es.is_empty() { - message.push_str("\n- missing in es-ES: "); - message.push_str(&missing_es_es.join(", ")); - } - if !orphaned_en_us.is_empty() { - message.push_str("\n- orphaned in en-US: "); - message.push_str(&orphaned_en_us.join(", ")); - } - if !orphaned_es_es.is_empty() { - message.push_str("\n- orphaned in es-ES: "); - message.push_str(&orphaned_es_es.join(", ")); - } - message -} - -pub(super) fn audit_localization_keys() -> Result<(), Box> { - let keys_path = Path::new("src/localization/keys.rs"); - let en_path = Path::new("locales/en-US/messages.ftl"); - let es_path = Path::new("locales/es-ES/messages.ftl"); - - let (declared, en_us_keys, es_es_keys) = load_key_sets(keys_path, en_path, es_path)?; - let results = compute_audit_differences(&declared, &en_us_keys, &es_es_keys); - if results.has_issues() { - Err(results.format_error_message().into()) - } else { - Ok(()) - } -} - -/// Extracts localization key values from `keys.rs`. -/// -/// Parses the `define_keys!` macro invocation to extract Fluent key identifiers. -/// Expects entries of the form: `CONST_NAME => "fluent-key-id",` within the -/// macro body. -/// -/// Implementation note: uses `extract_define_keys_body` to locate the macro -/// body and `parse_define_keys_body` to read values from `=> "..."` patterns. -/// -/// # Errors -/// -/// Returns an error if the macro cannot be parsed or no keys are found. -fn extract_key_constants(path: &Path) -> Result, Box> { - let source = fs::read_to_string(path)?; - let body = extract_define_keys_body(&source)?; - let keys = parse_define_keys_body(body)?; - if keys.is_empty() { - return Err(format!("no localization keys found in {}", path.display()).into()); - } - Ok(keys) -} - -fn extract_define_keys_body(source: &str) -> Result<&str, Box> { - let Some(macro_pos) = source.find(DEFINE_KEYS_MACRO) else { - return Err("define_keys! macro not found in localization keys".into()); - }; - let after_macro = source - .get(macro_pos + DEFINE_KEYS_MACRO.len()..) - .ok_or_else(|| "define_keys! macro start is out of range".to_owned())?; - let Some(open_brace) = after_macro.find('{') else { - return Err("define_keys! macro body is missing '{'".into()); - }; - let body_start = macro_pos + DEFINE_KEYS_MACRO.len() + open_brace + 1; - let remainder = source - .get(body_start..) - .ok_or_else(|| "define_keys! macro body is out of range".to_owned())?; - let body_len = find_matching_brace(remainder)?; - let body_end = body_start + body_len; - source - .get(body_start..body_end) - .ok_or_else(|| "define_keys! macro body slice invalid".into()) -} - -fn find_matching_brace(source: &str) -> Result> { - let mut depth = 0usize; - for (offset, ch) in source.char_indices() { - match ch { - '{' => depth += 1, - '}' => { - if depth == 0 { - return Ok(offset); - } - depth = depth.saturating_sub(1); - } - _ => {} - } - } - Err("define_keys! macro body is missing '}'".into()) -} - -fn parse_string_literal(source: &str, start: usize) -> Result<(String, usize), Box> { - if source.as_bytes().get(start) == Some(&b'"') { - return parse_regular_string_literal(source, start); - } - parse_raw_string_literal(source, start) -} - -fn parse_regular_string_literal( - source: &str, - start: usize, -) -> Result<(String, usize), Box> { - let remainder = source - .get(start + 1..) - .ok_or_else(|| "string literal start is out of range".to_owned())?; - let mut value = String::new(); - let mut escaped = false; - for (offset, ch) in remainder.char_indices() { - if escaped { - value.push(ch); - escaped = false; - continue; - } - match ch { - '\\' => escaped = true, - '"' => { - let end = start + 1 + offset + 1; - return Ok((value, end)); - } - _ => value.push(ch), - } - } - Err("unterminated string literal in localization keys".into()) -} - -fn parse_raw_string_literal(source: &str, start: usize) -> Result<(String, usize), Box> { - let bytes = source.as_bytes(); - let (mut idx, has_byte_prefix) = parse_raw_prefix(bytes, start)?; - if has_byte_prefix { - return Err("byte string literals are not supported in localization keys".into()); - } - let hash_count = count_hashes(bytes, &mut idx); - if bytes.get(idx) != Some(&b'"') { - return Err("raw string literal missing opening quote".into()); - } - idx += 1; - let content_start = idx; - let end = find_raw_string_end(bytes, idx, hash_count) - .ok_or_else(|| "unterminated raw string literal in localization keys".to_owned())?; - let content_end = end - 1 - hash_count; - let content = source - .get(content_start..content_end) - .ok_or_else(|| "raw string slice invalid".to_owned())?; - Ok((content.to_owned(), end)) -} - -fn parse_raw_prefix(bytes: &[u8], start: usize) -> Result<(usize, bool), Box> { - let mut idx = start; - let has_byte_prefix = bytes.get(idx) == Some(&b'b'); - if has_byte_prefix { - idx += 1; - } - if bytes.get(idx) != Some(&b'r') { - return Err("expected string literal after define_keys! =>".into()); - } - Ok((idx + 1, has_byte_prefix)) -} - -fn count_hashes(bytes: &[u8], idx: &mut usize) -> usize { - let mut count = 0usize; - while bytes.get(*idx) == Some(&b'#') { - count += 1; - *idx += 1; - } - count -} - -fn find_raw_string_end(bytes: &[u8], mut pos: usize, hash_count: usize) -> Option { - while let Some(byte) = bytes.get(pos) { - if *byte == b'"' && raw_hashes_match(bytes, pos + 1, hash_count) { - return Some(pos + 1 + hash_count); - } - pos += 1; - } - None -} - -fn raw_hashes_match(bytes: &[u8], start: usize, count: usize) -> bool { - (0..count).all(|idx| bytes.get(start + idx) == Some(&b'#')) -} - -fn is_line_comment(bytes: &[u8], idx: usize) -> bool { - bytes.get(idx) == Some(&b'/') && bytes.get(idx + 1) == Some(&b'/') -} - -fn is_block_comment(bytes: &[u8], idx: usize) -> bool { - bytes.get(idx) == Some(&b'/') && bytes.get(idx + 1) == Some(&b'*') -} - -fn skip_line_comment(bytes: &[u8], mut idx: usize) -> usize { - while let Some(byte) = bytes.get(idx) { - idx += 1; - if *byte == b'\n' { - break; - } - } - idx -} - -fn skip_block_comment(bytes: &[u8], mut idx: usize) -> usize { - while idx + 1 < bytes.len() { - if bytes.get(idx) == Some(&b'*') && bytes.get(idx + 1) == Some(&b'/') { - return idx + 2; - } - idx += 1; - } - bytes.len() -} - -fn skip_whitespace(bytes: &[u8], mut idx: usize) -> usize { - while let Some(byte) = bytes.get(idx) { - if byte.is_ascii_whitespace() { - idx += 1; - } else { - break; - } - } - idx -} - -/// Attempts to parse a key-value pair starting at the given index. -/// Returns the extracted key and the next index to continue parsing. -fn try_parse_key_at_arrow( - body: &str, - bytes: &[u8], - idx: usize, -) -> Result, Box> { - if bytes.get(idx) != Some(&b'=') || bytes.get(idx + 1) != Some(&b'>') { - return Ok(None); - } - - let next_idx = skip_whitespace(bytes, idx + 2); - if next_idx >= bytes.len() { - return Ok(None); - } - - let (value, next) = parse_string_literal(body, next_idx)?; - Ok(Some((value, next))) -} - -fn process_token_at( - body: &str, - bytes: &[u8], - idx: usize, -) -> Result, Box> { - if idx >= bytes.len() { - return Ok(None); - } - if is_line_comment(bytes, idx) { - return Ok(Some((String::new(), skip_line_comment(bytes, idx + 2)))); - } - if is_block_comment(bytes, idx) { - return Ok(Some((String::new(), skip_block_comment(bytes, idx + 2)))); - } - if let Some((key, next)) = try_parse_key_at_arrow(body, bytes, idx)? { - return Ok(Some((key, next))); - } - Ok(Some((String::new(), idx + 1))) -} - -fn parse_define_keys_body(body: &str) -> Result, Box> { - let bytes = body.as_bytes(); - let mut keys = BTreeSet::new(); - let mut idx = 0usize; - while idx < bytes.len() { - let Some((value, next)) = process_token_at(body, bytes, idx)? else { - break; - }; - if !value.is_empty() { - keys.insert(value); - } - idx = next; - } - Ok(keys) -} - -fn should_skip_ftl_line(trimmed: &str) -> bool { - trimmed.is_empty() || trimmed.starts_with('#') || trimmed.starts_with('.') -} - -/// Extract Fluent message identifiers from a `.ftl` bundle. -/// -/// This parser expects simple message declarations of the form `id = ...` and -/// skips blank lines, comments (starting with `#`), and attributes (starting -/// with `.`). Term identifiers (those starting with `-`) are ignored by design -/// because Netsuke only references message IDs in code. -/// -/// # Errors -/// -/// Returns an error if no keys are found in the bundle. -fn extract_ftl_keys(path: &Path) -> Result, Box> { - let source = fs::read_to_string(path)?; - let mut keys = BTreeSet::new(); - for line in source.lines() { - let trimmed = line.trim_start(); - if should_skip_ftl_line(trimmed) { - continue; - } - let Some((id_raw, _)) = trimmed.split_once('=') else { - continue; - }; - let id = id_raw.trim(); - if id.is_empty() || id.starts_with('-') { - continue; - } - keys.insert(id.to_owned()); - } - if keys.is_empty() { - return Err(format!("no Fluent keys found in {}", path.display()).into()); - } - Ok(keys) -} diff --git a/build_l10n_audit/byte_index.rs b/build_l10n_audit/byte_index.rs new file mode 100644 index 000000000..48a86a320 --- /dev/null +++ b/build_l10n_audit/byte_index.rs @@ -0,0 +1,40 @@ +//! A byte position within the source a scanner walks. +//! +//! Split from `scanner.rs` to keep that module within the repository's line +//! limit. The type is deliberately tiny: it exists so a position cannot be +//! confused with a count, both being `usize` underneath. + +/// A byte offset into a scanner's source. +/// +/// Positions and counts are both `usize` underneath, and the scanner passes +/// them side by side — a raw string literal's opening index next to its run of +/// hashes. Naming the position separately keeps the two from being swapped. +#[derive(Clone, Copy)] +pub(crate) struct ByteIndex(usize); + +impl ByteIndex { + /// The start of the parsed body. + pub(crate) const START: Self = Self(0); + + /// The position at byte `offset`. + pub(crate) const fn from_offset(offset: usize) -> Self { + Self(offset) + } + + pub(crate) const fn get(self) -> usize { + self.0 + } + + /// The position `delta` bytes further along. + pub(crate) const fn advance(self, delta: usize) -> Self { + Self(self.0 + delta) + } + + /// The position `delta` bytes earlier, or `None` when that would underflow. + pub(crate) const fn retreat(self, delta: usize) -> Option { + match self.0.checked_sub(delta) { + Some(offset) => Some(Self(offset)), + None => None, + } + } +} diff --git a/build_l10n_audit/compare.rs b/build_l10n_audit/compare.rs new file mode 100644 index 000000000..79678813f --- /dev/null +++ b/build_l10n_audit/compare.rs @@ -0,0 +1,190 @@ +//! Comparing one catalogue against the declared keys and the English source. +//! +//! The comparison is pure: it takes the parsed key sets and reports what is +//! wrong, leaving the reading of files and the walking of the registry to +//! `mod.rs`. That separation is what lets the rules below be tested directly. + +use super::ftl::MessageVariables; +use std::collections::BTreeSet; + +/// Findings for a single catalogue. +pub(super) struct LocaleFindings { + tag: String, + missing: Vec, + orphaned: Vec, + variable_mismatches: Vec, +} + +impl LocaleFindings { + /// Whether the catalogue matched the declared keys and the source. + /// + /// # Examples + /// + /// ```text + /// missing = [], orphaned = [], variable_mismatches = [] -> true + /// missing = ["cli.about"], orphaned = [], mismatches = [] -> false + /// ``` + pub(super) const fn is_clean(&self) -> bool { + self.missing.is_empty() && self.orphaned.is_empty() && self.variable_mismatches.is_empty() + } + + /// Append this catalogue's findings to `message`, one line per category. + /// + /// Clean findings append nothing, so a passing locale leaves no trace in + /// the build-failure text. + /// + /// # Examples + /// + /// ```text + /// tag = "fr", missing = ["cli.about"], orphaned = ["fr.extra"] + /// appends: "\n- missing in fr: cli.about\n- orphaned in fr: fr.extra" + /// tag = "fr", all empty + /// appends: nothing + /// ``` + fn append_to(&self, message: &mut String) { + append_section(message, &self.tag, "missing", &self.missing); + append_section(message, &self.tag, "orphaned", &self.orphaned); + append_section( + message, + &self.tag, + "variable mismatch", + &self.variable_mismatches, + ); + } +} + +/// Append one labelled finding line, or nothing when `entries` is empty. +/// +/// # Examples +/// +/// ```text +/// label = "missing", tag = "de", entries = ["a.key", "b.key"] +/// appends: "\n- missing in de: a.key, b.key" +/// entries = [] +/// appends: nothing +/// ``` +fn append_section(message: &mut String, tag: &str, label: &str, entries: &[String]) { + if entries.is_empty() { + return; + } + message.push_str("\n- "); + message.push_str(label); + message.push_str(" in "); + message.push_str(tag); + message.push_str(": "); + message.push_str(&entries.join(", ")); +} + +/// Render variable names for a diagnostic, sigils included. +/// +/// # Examples +/// +/// ```text +/// {"count", "path"} -> "$count $path" +/// {} -> "none" +/// ``` +/// +/// The empty set renders as `none` rather than an empty string so a message +/// reading "expected none, found $path" stays legible. +fn render_variables(names: &BTreeSet) -> String { + if names.is_empty() { + return "none".to_owned(); + } + names + .iter() + .map(|name| format!("${name}")) + .collect::>() + .join(" ") +} + +/// Describe one key whose variables differ from the source. +/// +/// # Examples +/// +/// ```text +/// key = "stdlib.path.io.failed", source = {"path"}, other = {"percorso"} +/// -> "stdlib.path.io.failed (expected $path, found $percorso)" +/// key = "cli.about", source = {}, other = {"extra"} +/// -> "cli.about (expected none, found $extra)" +/// ``` +fn describe_variable_mismatch( + key: &str, + source: &BTreeSet, + other: &BTreeSet, +) -> String { + format!( + "{key} (expected {}, found {})", + render_variables(source), + render_variables(other) + ) +} + +/// Messages whose interpolation variables differ from the English source. +/// +/// Only keys present in both are compared; a key absent from the catalogue is +/// already reported as missing. +/// +/// # Examples +/// +/// ```text +/// source = {"a": {"path"}}, other = {"a": {"path"}} -> [] +/// source = {"a": {"path"}}, other = {"a": {"percorso"}} -> ["a (expected $path, found $percorso)"] +/// source = {"a": {"path"}}, other = {} -> [] (reported as missing instead) +/// ``` +fn variable_mismatches(source: &MessageVariables, other: &MessageVariables) -> Vec { + source + .iter() + .filter_map(|(key, expected)| { + let found = other.get(key)?; + (found != expected).then(|| describe_variable_mismatch(key, expected, found)) + }) + .collect() +} + +/// Compare one catalogue against the declared keys and the English source. +/// +/// # Examples +/// +/// ```text +/// declared = {"a"}, catalogue = {"a"} -> clean +/// declared = {"a", "b"}, catalogue = {"a"} -> missing = ["b"] +/// declared = {"a"}, catalogue = {"a", "z"} -> orphaned = ["z"] +/// declared = {"a"}, catalogue = {"a"} with a different $variable +/// -> variable_mismatches = ["a (expected …, found …)"] +/// ``` +pub(super) fn audit_catalogue( + tag: &str, + declared: &BTreeSet, + source: &MessageVariables, + catalogue: &MessageVariables, +) -> LocaleFindings { + let present: BTreeSet = catalogue.keys().cloned().collect(); + LocaleFindings { + tag: tag.to_owned(), + missing: declared.difference(&present).cloned().collect(), + orphaned: present.difference(declared).cloned().collect(), + variable_mismatches: variable_mismatches(source, catalogue), + } +} + +/// Render every locale's findings into one build-failure message. +/// +/// Every offending locale appears, so one build reports them all rather than +/// surfacing them one rebuild at a time. +/// +/// # Examples +/// +/// ```text +/// [fr: missing ["a"], de: orphaned ["z"]] +/// -> "localization audit failed: +/// - missing in fr: a +/// - orphaned in de: z" +/// [] -> "localization audit failed:" (callers only build this when findings exist) +/// ``` +pub(super) fn build_error_message(findings: &[LocaleFindings]) -> String { + let mut message = String::from("localization audit failed:"); + for finding in findings { + finding.append_to(&mut message); + } + message +} diff --git a/build_l10n_audit/ftl.rs b/build_l10n_audit/ftl.rs new file mode 100644 index 000000000..50368bbdd --- /dev/null +++ b/build_l10n_audit/ftl.rs @@ -0,0 +1,121 @@ +//! Minimal Fluent parser used by the build-time localization audit. +//! +//! Only the subset of FTL that Netsuke's catalogues use is understood: simple +//! message declarations, multi-line message bodies (including `select` +//! expressions for plural categories), comments, and variable references. Terms +//! (identifiers starting with `-`) are ignored by design because Netsuke only +//! references message identifiers from code. + +use std::collections::{BTreeMap, BTreeSet}; +use std::error::Error; + +/// Message identifiers mapped to the variables their value interpolates. +pub(super) type MessageVariables = BTreeMap>; + +/// Whether `trimmed` opens a comment. +/// +/// Only meaningful for a line that starts an entry: an indented line is +/// pattern text even when it begins with `#`, so callers must rule out a +/// continuation first. +fn is_comment(trimmed: &str) -> bool { + trimmed.starts_with('#') +} + +/// A continuation line belongs to the message above it. +/// +/// Fluent defines U+0020 alone as indentation, so a tab-indented line is not a +/// continuation — treating it as one would attribute its variables to the +/// message above and hide a malformed entry. +fn is_continuation(line: &str, trimmed: &str) -> bool { + !trimmed.is_empty() && line.starts_with(' ') +} + +/// Split a declaration line into its message identifier and value. +/// +/// Returns both halves of the one `split_once` so the caller never has to +/// split the line a second time to reach the value. +fn message_identifier(trimmed: &str) -> Option<(&str, &str)> { + let (id_raw, value) = trimmed.split_once('=')?; + let id = id_raw.trim(); + let starts_identifier = id + .chars() + .next() + .is_some_and(|first| first.is_ascii_alphabetic()); + starts_identifier.then_some((id, value)) +} + +/// Collect `$variable` references from a message body. +fn collect_variables(body: &str, into: &mut BTreeSet) { + let mut rest = body; + while let Some(offset) = rest.find('$') { + let after = rest.get(offset + 1..).unwrap_or_default(); + let name: String = after + .chars() + .take_while(|ch| ch.is_ascii_alphanumeric() || *ch == '_') + .collect(); + if !name.is_empty() { + into.insert(name); + } + rest = after; + } +} + +/// Parse a catalogue into its message identifiers and interpolated variables. +/// +/// Takes the catalogue text rather than a path: reading is `read_source`'s +/// job, which keeps this parser free of an ambient path and testable without +/// staging files. +/// +/// # Errors +/// +/// Returns an error if the catalogue declares no messages. +pub(super) fn parse_catalogue(source: &str) -> Result> { + let mut messages = MessageVariables::new(); + let mut current: Option = None; + + for line in source.lines() { + let trimmed = line.trim(); + // A blank line does not end a pattern in Fluent; only the next entry + // does. Clearing here would drop the variables of every continuation + // after it. + if trimmed.is_empty() { + continue; + } + // Continuation is tested before comment. Fluent's comment syntax + // applies only to a line that starts an entry, so an indented line is + // pattern text whatever its first character — including `#`. Testing + // for a comment first would discard such a line and lose the + // variables it references. + if is_continuation(line, trimmed) { + append_continuation(&mut messages, current.as_deref(), trimmed); + continue; + } + if is_comment(trimmed) { + continue; + } + current = start_message(&mut messages, trimmed); + } + + if messages.is_empty() { + return Err("no Fluent messages found in the catalogue".into()); + } + Ok(messages) +} + +fn append_continuation(messages: &mut MessageVariables, current: Option<&str>, trimmed: &str) { + let Some(variables) = current.and_then(|id| messages.get_mut(id)) else { + return; + }; + collect_variables(trimmed, variables); +} + +/// Begin a new message, returning its identifier when the line declares one. +/// +/// The caller's loop has already skipped blank lines, so the line is known to +/// be non-empty here. +fn start_message(messages: &mut MessageVariables, trimmed: &str) -> Option { + let (id, value) = message_identifier(trimmed)?; + let variables = messages.entry(id.to_owned()).or_default(); + collect_variables(value, variables); + Some(id.to_owned()) +} diff --git a/build_l10n_audit/keys.rs b/build_l10n_audit/keys.rs new file mode 100644 index 000000000..58d9608fe --- /dev/null +++ b/build_l10n_audit/keys.rs @@ -0,0 +1,87 @@ +//! Extraction of Fluent message identifiers declared in Rust source. +//! +//! Parses the `define_keys!` macro in `src/localization/keys.rs` so the build +//! audit can compare the keys the code references against the keys each +//! catalogue provides. + +#[path = "scanner.rs"] +mod scanner; + +use scanner::{ByteIndex, DefineKeysParser}; +use std::collections::BTreeSet; +use std::error::Error; + +const DEFINE_KEYS_MACRO: &str = "define_keys!"; + +/// Extracts localization key values from `keys.rs`. +/// +/// Parses the `define_keys!` macro invocation to extract Fluent key identifiers. +/// Expects entries of the form: `CONST_NAME => "fluent-key-id",` within the +/// macro body. +/// +/// Implementation note: uses `extract_define_keys_body` to locate the macro +/// body and `parse_define_keys_body` to read values from `=> "..."` patterns. +/// +/// # Errors +/// +/// Returns an error if the macro cannot be parsed or no keys are found. +pub(super) fn extract_key_constants(source: &str) -> Result, Box> { + let body = extract_define_keys_body(source)?; + let keys = parse_define_keys_body(body)?; + if keys.is_empty() { + return Err("no localization keys found in the localization key source".into()); + } + Ok(keys) +} + +fn extract_define_keys_body(source: &str) -> Result<&str, Box> { + // Scanned rather than searched: `define_keys!` named in a doc comment or + // quoted in a string is not the invocation, and reading from there would + // take the wrong text as the macro body. + let Some(macro_pos) = DefineKeysParser::new(source).find_in_source(DEFINE_KEYS_MACRO) else { + return Err("define_keys! macro not found in localization keys".into()); + }; + // Trivia may sit between the macro name and its delimiter, and a brace + // inside it is not the delimiter: `define_keys! /* { */ { … }` is valid + // Rust. + let parser = DefineKeysParser::new(source); + let after_name = macro_pos + .checked_add(DEFINE_KEYS_MACRO.len()) + .ok_or_else(|| "define_keys! macro start is out of range".to_owned())?; + let Some(body_start) = parser.body_start_after(ByteIndex::from_offset(after_name)) else { + return Err("define_keys! macro body is missing '{'".into()); + }; + let remainder = source + .get(body_start..) + .ok_or_else(|| "define_keys! macro body is out of range".to_owned())?; + let body_len = find_matching_brace(remainder)?; + let body_end = body_start + body_len; + source + .get(body_start..body_end) + .ok_or_else(|| "define_keys! macro body slice invalid".into()) +} + +/// Offset of the `}` closing a body that begins at the start of `source`. +/// +/// Braces inside comments and string literals do not nest, so the scan skips +/// both. A doc comment mentioning `}` or a key whose value contains one would +/// otherwise end the body early and silently truncate the declared key set. +fn find_matching_brace(source: &str) -> Result> { + DefineKeysParser::new(source).find_body_end() +} + +fn parse_define_keys_body(body: &str) -> Result, Box> { + let parser = DefineKeysParser::new(body); + let mut keys = BTreeSet::new(); + let mut index = ByteIndex::START; + while !parser.is_exhausted(index) { + let Some((value, next)) = parser.process_token_at(index)? else { + break; + }; + if !value.is_empty() { + keys.insert(value); + } + index = next; + } + Ok(keys) +} diff --git a/build_l10n_audit/metadata.rs b/build_l10n_audit/metadata.rs new file mode 100644 index 000000000..277919ecc --- /dev/null +++ b/build_l10n_audit/metadata.rs @@ -0,0 +1,340 @@ +//! Reading the `ortho_config` locale list out of `Cargo.toml`. +//! +//! Cargo metadata cannot call into Rust, so the locale list is necessarily +//! duplicated between the registry and the manifest. The audit compares the +//! two, which means it has to read the manifest without pulling in a TOML +//! parser as a build dependency. This module does that reading, narrowly. + +/// Read the `locales = [...]` array from the `ortho_config` metadata table. +/// +/// The key is matched as a whole assignment at the start of a line, so neither +/// a comment mentioning locales nor a neighbouring key such as `extra_locales` +/// can be picked up in its place. The array itself may span lines. +/// +/// Returns `None` when the table or the key is absent, or when the array is +/// unterminated. +pub(super) fn parse_metadata_locales(manifest: &str) -> Option> { + let table = ortho_config_table(manifest)?; + let assignment = locales_assignment(table)?; + let (_, open) = assignment.split_once('[')?; + let (entries, _) = open.split_once(']')?; + Some( + entries + .split(',') + .map(|entry| entry.trim().trim_matches('"')) + .filter(|entry| !entry.is_empty()) + .collect(), + ) +} + +/// The body of the `[package.metadata.ortho_config]` table. +/// +/// The header is matched only where it begins a line, so a commented-out or +/// quoted mention of the table earlier in the manifest does not capture the +/// search and return the text above the real table. The table ends at the next +/// table header — the next `[` beginning a line — judged by the same rule as +/// the header itself, so a `[` inside a multiline string is content rather +/// than a boundary and cannot truncate the table early. +fn ortho_config_table(manifest: &str) -> Option<&str> { + const HEADER: &str = "[package.metadata.ortho_config]"; + let start = manifest + .match_indices(HEADER) + .find(|(start, _)| begins_a_line(manifest, *start)) + .map(|(start, _)| start)?; + let tail = manifest.get(start.saturating_add(HEADER.len())..)?; + tail.get(..table_end(tail)) +} + +/// Where the table body ends within `tail`. +/// +/// This is the offset of the next table header, or the whole length when no +/// further header follows. Scanning `tail` alone is sound because the header +/// match above already established that the header does not sit inside a +/// multiline string, so the string state at the start of `tail` is "outside". +/// +/// A candidate must also be a header, not merely begin a line: inside a +/// multiline array a nested value such as `["decoy"],` can open a line too, +/// and taking it for a header would truncate the table above the keys that +/// follow it. Scanning continues past such lines. +fn table_end(tail: &str) -> usize { + tail.match_indices("\n[") + .map(|(newline, _)| newline.saturating_add(1)) + .find(|bracket| header_starts_at(tail, *bracket)) + .unwrap_or(tail.len()) +} + +/// Whether a table header begins at `start` within `tail`. +/// +/// Three rules, each excluding one impostor. The bracket must begin a line +/// outside any string, or it is content. Its position must sit at array depth +/// zero, or it is a nested value inside a multiline array — quoted headers +/// such as `["release metadata"]` and quoted array elements are lexically +/// identical, so only the surrounding context can tell them apart. And its +/// line must read as a header, or it is malformed input no rule should match. +fn header_starts_at(tail: &str, start: usize) -> bool { + begins_a_line(tail, start) + && tail + .get(..start) + .is_some_and(|before| scan_prefix(before).array_depth == 0) + && tail + .get(start..) + .and_then(|rest| rest.lines().next()) + .is_some_and(is_table_header) +} + +/// Whether `line` declares a `[table]` or `[[array-of-tables]]` header. +/// +/// The bracket content must read as a TOML key — dotted segments, each bare +/// or quoted — and the line must end after the closing bracket, save for a +/// comment. Array context is the caller's job: at depth zero a well-formed +/// key in brackets cannot be a value, since bare words are not TOML values +/// and a top-level line cannot open with one. +fn is_table_header(line: &str) -> bool { + let outer = line.strip_prefix('[').unwrap_or(line); + let body = outer.strip_prefix('[').unwrap_or(outer); + let Some((name, rest)) = split_header_name(body) else { + return false; + }; + let trailing = rest.trim_start_matches(']').trim(); + header_names_a_key(name) && (trailing.is_empty() || trailing.starts_with('#')) +} + +/// Split the header body at its closing bracket, honouring quoted segments. +/// +/// A `]` inside a quoted segment is key content, so the split lands on the +/// first closing bracket outside quotes, with escapes honoured inside basic +/// strings. `None` means the line never closes its bracket, which no header +/// does. +fn split_header_name(body: &str) -> Option<(&str, &str)> { + let mut index = 0; + while let Some(ch) = body.get(index..)?.chars().next() { + match ch { + '"' | '\'' => { + let inner = body.get(index.saturating_add(1)..)?; + let close = closing_quote_at(inner, ch)?; + index = index.saturating_add(close).saturating_add(2); + } + ']' => return Some((body.get(..index)?, body.get(index..)?)), + _ => index = index.saturating_add(ch.len_utf8()), + } + } + None +} + +/// The byte offset of the quote closing a segment opened with `quote`. +/// +/// A backslash escapes the next character in a basic (double-quoted) string, +/// so `\"` is content rather than the close; a literal (single-quoted) string +/// takes its contents verbatim. This mirrors `step_single_line`. +fn closing_quote_at(inner: &str, quote: char) -> Option { + let mut escaped = false; + for (index, ch) in inner.char_indices() { + if escaped { + escaped = false; + } else if ch == '\\' && quote == '"' { + escaped = true; + } else if ch == quote { + return Some(index); + } + } + None +} + +/// Whether `name` reads as a TOML key: dotted segments, bare or quoted. +/// +/// Bare segments draw on the bare-key alphabet; quoted segments accept any +/// content up to their closing quote, with `\"` inside a basic string read as +/// content rather than the close. +fn header_names_a_key(name: &str) -> bool { + let mut rest = name.trim(); + if rest.is_empty() { + return false; + } + loop { + let Some(after) = key_segment_after(rest) else { + return false; + }; + rest = after.trim_start(); + let Some(next) = rest.strip_prefix('.') else { + return rest.is_empty(); + }; + rest = next.trim_start(); + } +} + +/// Consume one key segment at the head of `rest`, returning what follows. +fn key_segment_after(rest: &str) -> Option<&str> { + if let Some(quote) = rest.chars().next().filter(|ch| matches!(ch, '"' | '\'')) { + let inner = rest.get(1..)?; + let end = closing_quote_at(inner, quote)?; + inner.get(end.saturating_add(1)..) + } else { + let end = rest + .find(|ch: char| !(ch.is_ascii_alphanumeric() || matches!(ch, '-' | '_'))) + .unwrap_or(rest.len()); + (end > 0).then(|| rest.get(end..)).flatten() + } +} + +/// The table text from the `locales` assignment onwards. +fn locales_assignment(table: &str) -> Option<&str> { + table + .match_indices("locales") + .filter(|(start, _)| begins_a_line(table, *start)) + .find_map(|(start, _)| { + let rest = table.get(start..)?; + is_locales_assignment(rest).then_some(rest) + }) +} + +/// Whether `start` begins a line of TOML source. +/// +/// Two things disqualify it. A word character earlier on the line means this is +/// the tail of a longer key — the `locales` inside `extra_locales`. Being +/// inside a multiline string means it is content rather than source: a +/// `description` written with triple quotes can contain a line reading +/// `[package.metadata.ortho_config]`, and selecting it would make the audit +/// read a prose paragraph as the table. +fn begins_a_line(table: &str, start: usize) -> bool { + let Some(before) = table.get(..start) else { + return false; + }; + let line_start = before + .rsplit('\n') + .next() + .is_some_and(|indent| indent.trim().is_empty()); + line_start && !inside_multiline_string(before) +} + +/// The two TOML multiline string delimiters. +const MULTILINE_DELIMITERS: [&str; 2] = ["\"\"\"", "'''"]; + +/// Lexical state at the end of a scanned prefix. +struct ScanState { + /// The multiline string delimiter still open, if any. + open: Option<&'static str>, + /// Array brackets opened outside strings and comments and not yet closed. + /// + /// Table headers self-balance on their own line, so a non-zero depth + /// means the position lies inside a multiline array value, where a + /// line-initial bracket is a value rather than a header. + array_depth: usize, +} + +/// Whether `prefix` ends inside a multiline string. +fn inside_multiline_string(prefix: &str) -> bool { + scan_prefix(prefix).open.is_some() +} + +/// Scan `prefix`, tracking strings, comments, and array brackets. +/// +/// Each multiline delimiter toggles the string state, and the two quote +/// styles are tracked separately because neither terminates the other. +/// Single-line strings are tracked so their contents cannot toggle anything; +/// comments are skipped outside strings for the same reason. Brackets are +/// counted only outside strings and comments, and the count saturates rather +/// than underflows on the `]` that closes a header's own bracket. +fn scan_prefix(prefix: &str) -> ScanState { + let mut state = ScanState { + open: None, + array_depth: 0, + }; + let mut single: Option = None; + let mut escaped = false; + let mut in_comment = false; + let mut chars = prefix.char_indices(); + while let Some((index, ch)) = chars.next() { + if in_comment { + in_comment = ch != '\n'; + continue; + } + if single.is_some() { + (single, escaped) = step_single_line(single, escaped, ch); + continue; + } + if let Some(found) = multiline_delimiter_at(prefix, index, state.open) { + state.open = toggled(state.open, found); + // Skip the delimiter's remaining two characters. + chars.next(); + chars.next(); + continue; + } + if state.open.is_some() { + continue; + } + (in_comment, single) = step_plain(&mut state, ch); + } + state +} + +/// The multiline state after a delimiter is read: closed if open, else opened. +const fn toggled(open: Option<&'static str>, found: &'static str) -> Option<&'static str> { + if open.is_some() { None } else { Some(found) } +} + +/// Advance the scan by one plain character, outside strings and comments. +/// +/// Returns the new comment flag and single-line string opener; the array +/// depth is adjusted in place. +const fn step_plain(state: &mut ScanState, ch: char) -> (bool, Option) { + match ch { + '#' => (true, None), + '[' => { + state.array_depth = state.array_depth.saturating_add(1); + (false, None) + } + ']' => { + state.array_depth = state.array_depth.saturating_sub(1); + (false, None) + } + _ => (false, single_line_opener(ch)), + } +} + +/// Advance a single-line string scan by one character. +/// +/// Returns the quote still open, if any, and whether the next character is +/// escaped. Only a basic string honours the escape; a literal string takes its +/// contents verbatim. +const fn step_single_line(single: Option, escaped: bool, ch: char) -> (Option, bool) { + let Some(quote) = single else { + return (None, false); + }; + if escaped { + return (Some(quote), false); + } + if ch == '\\' && quote == '"' { + return (Some(quote), true); + } + if ch == quote || ch == '\n' { + return (None, false); + } + (Some(quote), false) +} + +/// The multiline delimiter starting at `index`, if one does. +/// +/// A window that does not land on a character boundary is not a delimiter, so +/// `get` returning `None` yields `None` rather than ending the scan — a +/// multi-byte character earlier in the manifest must not truncate it. +fn multiline_delimiter_at(prefix: &str, index: usize, open: Option<&str>) -> Option<&'static str> { + let window = prefix.get(index..index.saturating_add(3))?; + MULTILINE_DELIMITERS + .into_iter() + .find(|candidate| *candidate == window) + .filter(|candidate| open.is_none_or(|current| current == *candidate)) +} + +/// The quote opening a single-line string, if `ch` is one. +const fn single_line_opener(ch: char) -> Option { + match ch { + '"' | '\'' => Some(ch), + _ => None, + } +} + +/// Whether `rest` opens with `locales` followed by an `=`. +fn is_locales_assignment(rest: &str) -> bool { + rest.strip_prefix("locales") + .is_some_and(|after| after.trim_start().starts_with('=')) +} diff --git a/build_l10n_audit/mod.rs b/build_l10n_audit/mod.rs new file mode 100644 index 000000000..b1b0ed671 --- /dev/null +++ b/build_l10n_audit/mod.rs @@ -0,0 +1,138 @@ +//! Localization audit for the build script. +//! +//! Compares the keys declared by `define_keys!` in `src/localization/keys.rs` +//! with every catalogue named by the locale registry in +//! `src/locale_catalogues.rs`. The audit fails the build when a catalogue is +//! missing a declared key, carries an orphaned key, or interpolates a different +//! set of variables from the English source for a shared message. +//! +//! The registry is the sole locale list; `Cargo.toml`'s +//! `package.metadata.ortho_config.locales` array is checked against it rather +//! than being a second source of truth. + +mod compare; +mod ftl; +mod keys; +mod metadata; + +use crate::locale_catalogues::{LocaleCatalogue, SOURCE_LOCALE, SUPPORTED_LOCALES}; +use compare::{audit_catalogue, build_error_message}; +use ftl::MessageVariables; +use metadata::parse_metadata_locales; +use std::error::Error; +use std::path::{Path, PathBuf}; + +const KEYS_PATH: &str = "src/localization/keys.rs"; +const CARGO_MANIFEST: &str = "Cargo.toml"; + +/// Path of the catalogue for `tag`, relative to the repository root. +pub(crate) fn catalogue_path(tag: &str) -> PathBuf { + catalogue_path_in(Path::new(""), tag) +} + +/// Path of the catalogue for `tag`, beneath `root`. +fn catalogue_path_in(root: &Path, tag: &str) -> PathBuf { + root.join("locales").join(tag).join("messages.ftl") +} + +/// Verify that `Cargo.toml` advertises exactly the registry's locales. +/// +/// The metadata is consumed by `ortho_config` tooling, so it must not drift +/// from the catalogues the binary actually embeds. +fn audit_cargo_metadata(root: &Path) -> Result<(), Box> { + let manifest = read_source(&root.join(CARGO_MANIFEST))?; + let declared = parse_metadata_locales(&manifest) + .ok_or("Cargo.toml is missing package.metadata.ortho_config.locales")?; + let expected: Vec<&str> = SUPPORTED_LOCALES.iter().map(LocaleCatalogue::tag).collect(); + if declared == expected { + return Ok(()); + } + Err(format!( + "Cargo.toml package.metadata.ortho_config.locales does not match the locale registry:\n\ + - Cargo.toml: {}\n- registry: {}", + declared.join(", "), + expected.join(", ") + ) + .into()) +} + +/// Read `path`, naming it in the error. +/// +/// Every filesystem read the audit performs goes through here. The parsers +/// below it take `&str`, so this module is the only one holding an ambient +/// path, and they stay testable without staging files. +fn read_source(path: &Path) -> Result> { + std::fs::read_to_string(path) + .map_err(|err| format!("failed to read {}: {err}", path.display()).into()) +} + +/// Parse the catalogue at `path`, naming it if parsing fails. +/// +/// The parser takes text and so cannot name the file itself; the path is added +/// back here, where it is known, so a failure still says which catalogue. +fn parse_catalogue_at(path: &Path) -> Result> { + ftl::parse_catalogue(&read_source(path)?) + .map_err(|err| format!("{}: {err}", path.display()).into()) +} + +fn source_catalogue_variables(root: &Path) -> Result> { + parse_catalogue_at(&catalogue_path_in(root, SOURCE_LOCALE)) +} + +/// Audit every registered locale, reporting the comparison findings together. +/// +/// This is the audit's entry point, called from `build.rs`. It checks that +/// `Cargo.toml`'s locale metadata matches the registry, then compares each +/// catalogue against the keys `define_keys!` declares and against the English +/// source's interpolation variables. +/// +/// The two kinds of failure surface differently. A catalogue that disagrees +/// with the source is a *finding*: every locale is compared and the findings +/// are reported in one message, so a translator sees the whole list rather +/// than fixing one key per build. Anything that stops the audit running at all +/// — drifted metadata, an unreadable file, an unparseable key macro — aborts +/// at the point it is met, because there is nothing further to compare. +/// +/// # Errors +/// +/// Returns an error when the metadata has drifted from the registry, when a +/// catalogue cannot be read, or when any catalogue is missing a declared key, +/// carries an orphaned key, or interpolates the wrong variables. The message +/// names every offending locale and key so one build reports them all. +pub(super) fn audit_localization_keys() -> Result<(), Box> { + audit_localization_keys_in(Path::new("")) +} + +/// Audit the tree rooted at `root`. +/// +/// Split from [`audit_localization_keys`] so tests can run the whole +/// orchestration against the checked-in repository without depending on the +/// process working directory. The build script keeps calling the entry point +/// above, which passes an empty root and so reads the same relative paths it +/// always did. +/// +/// # Errors +/// +/// As [`audit_localization_keys`]. +pub(crate) fn audit_localization_keys_in(root: &Path) -> Result<(), Box> { + audit_cargo_metadata(root)?; + let keys_path = root.join(KEYS_PATH); + let declared = keys::extract_key_constants(&read_source(&keys_path)?) + .map_err(|err| format!("{}: {err}", keys_path.display()))?; + let source = source_catalogue_variables(root)?; + + let mut findings = Vec::new(); + for entry in SUPPORTED_LOCALES { + let catalogue = parse_catalogue_at(&catalogue_path_in(root, entry.tag()))?; + let result = audit_catalogue(entry.tag(), &declared, &source, &catalogue); + if !result.is_clean() { + findings.push(result); + } + } + + if findings.is_empty() { + Ok(()) + } else { + Err(build_error_message(&findings).into()) + } +} diff --git a/build_l10n_audit/scanner.rs b/build_l10n_audit/scanner.rs new file mode 100644 index 000000000..cdfcfcdcd --- /dev/null +++ b/build_l10n_audit/scanner.rs @@ -0,0 +1,396 @@ +//! Byte-level scanner for the body of a `define_keys!` invocation. +//! +//! Split out of `keys.rs` so that the extraction entry points stay readable +//! next to the scanning primitives they drive. The scanner is deliberately +//! narrow: it recognizes Rust comments and string literals well enough to step +//! over them, which is all the audit needs in order to find `=> "..."` keys +//! and the macro's closing brace. + +use std::error::Error; + +#[path = "byte_index.rs"] +mod byte_index; + +pub(crate) use byte_index::ByteIndex; + +/// A scanner over the body of a `define_keys!` invocation. +/// +/// The scan needs the body two ways: as `str`, to slice out literal contents +/// without re-decoding, and as bytes, to test one character at a time. Holding +/// both on one value keeps them paired, so no caller can pass a byte slice +/// belonging to a different string from the one it slices. +pub(super) struct DefineKeysParser<'source> { + source: &'source str, + bytes: &'source [u8], +} + +impl<'source> DefineKeysParser<'source> { + pub(super) const fn new(source: &'source str) -> Self { + Self { + source, + bytes: source.as_bytes(), + } + } + + /// Whether `index` has run past the end of the body. + pub(super) const fn is_exhausted(&self, index: ByteIndex) -> bool { + index.get() >= self.bytes.len() + } + + fn byte_at(&self, index: ByteIndex) -> Option<&u8> { + self.bytes.get(index.get()) + } + + fn byte_is(&self, index: ByteIndex, expected: u8) -> bool { + self.byte_at(index) == Some(&expected) + } + + /// Parse the string literal starting at `start`, returning its value and + /// the position just past it. + fn parse_string_literal( + &self, + start: ByteIndex, + ) -> Result<(String, ByteIndex), Box> { + if self.byte_is(start, b'"') { + return self.parse_regular_string_literal(start); + } + self.parse_raw_string_literal(start) + } + + fn parse_regular_string_literal( + &self, + start: ByteIndex, + ) -> Result<(String, ByteIndex), Box> { + let content_start = start.advance(1); + let remainder = self + .source + .get(content_start.get()..) + .ok_or_else(|| "string literal start is out of range".to_owned())?; + let mut value = String::new(); + let mut escaped = false; + for (offset, ch) in remainder.char_indices() { + if escaped { + value.push(ch); + escaped = false; + continue; + } + match ch { + '\\' => escaped = true, + '"' => return Ok((value, content_start.advance(offset + 1))), + _ => value.push(ch), + } + } + Err("unterminated string literal in localization keys".into()) + } + + fn parse_raw_string_literal( + &self, + start: ByteIndex, + ) -> Result<(String, ByteIndex), Box> { + let (after_prefix, has_byte_prefix) = self.parse_raw_prefix(start)?; + if has_byte_prefix { + return Err("byte string literals are not supported in localization keys".into()); + } + let (hash_count, after_hashes) = self.count_hashes(after_prefix); + if !self.byte_is(after_hashes, b'"') { + return Err("raw string literal missing opening quote".into()); + } + let content_start = after_hashes.advance(1); + let end = self + .find_raw_string_end(content_start, hash_count) + .ok_or_else(|| "unterminated raw string literal in localization keys".to_owned())?; + let content = end + .retreat(hash_count + 1) + .and_then(|content_end| self.source.get(content_start.get()..content_end.get())) + .ok_or_else(|| "raw string slice invalid".to_owned())?; + Ok((content.to_owned(), end)) + } + + /// Consume an optional `b` prefix and the mandatory `r`, reporting whether + /// the literal was a byte string. + fn parse_raw_prefix(&self, start: ByteIndex) -> Result<(ByteIndex, bool), Box> { + let has_byte_prefix = self.byte_is(start, b'b'); + let raw_marker = if has_byte_prefix { + start.advance(1) + } else { + start + }; + if !self.byte_is(raw_marker, b'r') { + return Err("expected string literal after define_keys! =>".into()); + } + Ok((raw_marker.advance(1), has_byte_prefix)) + } + + /// Count the run of `#` characters at `start`, returning the count and the + /// position just past the run. + fn count_hashes(&self, start: ByteIndex) -> (usize, ByteIndex) { + let mut count = 0usize; + let mut index = start; + while self.byte_is(index, b'#') { + count += 1; + index = index.advance(1); + } + (count, index) + } + + fn find_raw_string_end(&self, start: ByteIndex, hash_count: usize) -> Option { + let mut index = start; + while let Some(byte) = self.byte_at(index) { + if *byte == b'"' && self.raw_hashes_match(index.advance(1), hash_count) { + return Some(index.advance(hash_count + 1)); + } + index = index.advance(1); + } + None + } + + fn raw_hashes_match(&self, start: ByteIndex, count: usize) -> bool { + (0..count).all(|offset| self.byte_is(start.advance(offset), b'#')) + } + + fn is_line_comment(&self, index: ByteIndex) -> bool { + self.byte_is(index, b'/') && self.byte_is(index.advance(1), b'/') + } + + fn is_block_comment(&self, index: ByteIndex) -> bool { + self.byte_is(index, b'/') && self.byte_is(index.advance(1), b'*') + } + + fn skip_line_comment(&self, start: ByteIndex) -> ByteIndex { + let mut index = start; + while let Some(byte) = self.byte_at(index) { + let is_newline = *byte == b'\n'; + index = index.advance(1); + if is_newline { + break; + } + } + index + } + + /// Skip to just past the `*/` closing the block comment opened before + /// `start`. + /// + /// Rust block comments nest, so `/* /* */ */` is one comment. Stopping at + /// the first `*/` would leave the scan inside the outer comment and read + /// its remainder as source. + fn skip_block_comment(&self, start: ByteIndex) -> ByteIndex { + let mut index = start; + let mut depth = 1usize; + while index.advance(1).get() < self.bytes.len() { + if self.is_block_comment(index) { + depth = depth.saturating_add(1); + index = index.advance(2); + continue; + } + if !self.closes_block_comment(index) { + index = index.advance(1); + continue; + } + depth = depth.saturating_sub(1); + index = index.advance(2); + if depth == 0 { + return index; + } + } + ByteIndex::from_offset(self.bytes.len()) + } + + /// Whether a `*/` sits at `index`. + fn closes_block_comment(&self, index: ByteIndex) -> bool { + self.byte_is(index, b'*') && self.byte_is(index.advance(1), b'/') + } + + fn skip_whitespace(&self, start: ByteIndex) -> ByteIndex { + let mut index = start; + while self.byte_at(index).is_some_and(u8::is_ascii_whitespace) { + index = index.advance(1); + } + index + } + + /// Attempts to parse a key-value pair starting at the given index. + /// Returns the extracted key and the next index to continue parsing. + fn try_parse_key_at_arrow( + &self, + index: ByteIndex, + ) -> Result, Box> { + if !self.byte_is(index, b'=') || !self.byte_is(index.advance(1), b'>') { + return Ok(None); + } + + let literal_start = self.skip_whitespace(index.advance(2)); + if self.is_exhausted(literal_start) { + return Ok(None); + } + + let (value, next) = self.parse_string_literal(literal_start)?; + Ok(Some((value, next))) + } + + /// Whether a string literal opens at `index`. + /// + /// Recognizes `"…"`, `r"…"`, and `r#*"…"#*`, plus the byte-string forms so + /// that a `b"…"` is skipped as a literal rather than scanned as source. + fn starts_string_literal(&self, index: ByteIndex) -> bool { + if self.byte_is(index, b'"') { + return true; + } + let raw_marker = if self.byte_is(index, b'b') { + index.advance(1) + } else { + index + }; + if !self.byte_is(raw_marker, b'r') { + return false; + } + let (_, after_hashes) = self.count_hashes(raw_marker.advance(1)); + self.byte_is(after_hashes, b'"') + } + + /// Skip the comment or string literal at `index`. + /// + /// Returns `None` when `index` opens neither, leaving the caller to decide + /// what the byte means. Both the key scan and the brace scan need to step + /// over these regions, and for the same reason: their contents are not + /// source. + fn skip_comment_or_literal( + &self, + index: ByteIndex, + ) -> Result, Box> { + if self.is_line_comment(index) { + return Ok(Some(self.skip_line_comment(index.advance(2)))); + } + if self.is_block_comment(index) { + return Ok(Some(self.skip_block_comment(index.advance(2)))); + } + if self.starts_string_literal(index) { + let (_, next) = self.parse_string_literal(index)?; + return Ok(Some(next)); + } + Ok(None) + } + + /// Whether `needle` starts at `index` and is not the tail of a longer + /// identifier. + /// + /// `other_define_keys!` contains `define_keys!`, so a bare prefix test + /// would select the wrong macro. + fn matches_whole_identifier(&self, index: ByteIndex, needle: &str) -> bool { + let starts_here = self + .source + .get(index.get()..) + .is_some_and(|rest| rest.starts_with(needle)); + if !starts_here { + return false; + } + index.retreat(1).is_none_or(|before| { + self.byte_at(before) + .is_none_or(|byte| !byte.is_ascii_alphanumeric() && *byte != b'_') + }) + } + + /// Offset of `needle` where it appears as source, not inside a comment or + /// a string literal. + /// + /// `str::find` would match `define_keys!` written in a doc comment or + /// quoted in a string, and the audit would then read that text as the + /// macro body. + pub(super) fn find_in_source(&self, needle: &str) -> Option { + let mut index = ByteIndex::START; + while !self.is_exhausted(index) { + if let Ok(Some(next)) = self.skip_comment_or_literal(index) { + index = next; + continue; + } + if self.matches_whole_identifier(index, needle) { + return Some(index.get()); + } + index = index.advance(1); + } + None + } + + /// Offset just past the `{` that opens the body, starting the search at + /// `start`. + /// + /// Trivia between the macro name and its delimiter is skipped, so + /// `define_keys! /* { */ {` opens at the real brace. Taking the commented + /// one would make the scan treat the real brace as nested and never find + /// the body's end. + pub(super) fn body_start_after(&self, start: ByteIndex) -> Option { + let mut index = start; + while !self.is_exhausted(index) { + if let Ok(Some(next)) = self.skip_comment_or_literal(index) { + index = next; + continue; + } + if self.byte_is(index, b'{') { + return Some(index.advance(1).get()); + } + index = index.advance(1); + } + None + } + + /// Offset of the `}` that closes the body opening at the start of `self`. + /// + /// A literal that fails to parse is stepped over one byte at a time rather + /// than reported here. The key scan runs over the same text and diagnoses + /// malformed literals precisely; failing first, from the brace scan, would + /// replace those messages with a vaguer one. + /// + /// # Errors + /// + /// Returns an error when the body is never closed. + pub(super) fn find_body_end(&self) -> Result> { + let mut depth = 0usize; + let mut index = ByteIndex::START; + while !self.is_exhausted(index) { + if let Ok(Some(next)) = self.skip_comment_or_literal(index) { + index = next; + continue; + } + if self.byte_is(index, b'}') && depth == 0 { + return Ok(index.get()); + } + depth = self.depth_after(index, depth); + index = index.advance(1); + } + Err("define_keys! macro body is missing '}'".into()) + } + + /// The brace depth after consuming the byte at `index`. + /// + /// The closing brace of the body itself never reaches here; the caller + /// returns on it while the depth is still zero. + fn depth_after(&self, index: ByteIndex, depth: usize) -> usize { + if self.byte_is(index, b'{') { + depth.saturating_add(1) + } else if self.byte_is(index, b'}') { + depth.saturating_sub(1) + } else { + depth + } + } + + /// Consume one token at `index`, yielding any key it declares. + /// + /// Tokens that declare no key yield an empty string alongside the position + /// to resume from, so the caller advances uniformly. + pub(super) fn process_token_at( + &self, + index: ByteIndex, + ) -> Result, Box> { + if self.is_exhausted(index) { + return Ok(None); + } + if let Some((key, next)) = self.try_parse_key_at_arrow(index)? { + return Ok(Some((key, next))); + } + if let Some(next) = self.skip_comment_or_literal(index)? { + return Ok(Some((String::new(), next))); + } + Ok(Some((String::new(), index.advance(1)))) + } +} diff --git a/docs/contents.md b/docs/contents.md index 924d52ff5..a89d31f58 100644 --- a/docs/contents.md +++ b/docs/contents.md @@ -55,8 +55,9 @@ operator, user, and contributor references are easier to find. template standard-library reference with executable YAML and Jinja examples. - [ortho-config-users-guide.md](ortho-config-users-guide.md): Configuration system guide and precedence reference. -- [translators-guide.md](translators-guide.md): Localization workflow and - translation guidance. +- [translators-guide.md](translators-guide.md): Localization workflow, + translation guidance, the locale registry that owns the supported-tag list, + and the fallback policy that keeps regional and script variants distinct. ## Contributor guidance diff --git a/docs/developers-guide.md b/docs/developers-guide.md index 0c0865ddd..ff9568a05 100644 --- a/docs/developers-guide.md +++ b/docs/developers-guide.md @@ -26,6 +26,122 @@ as the durable architecture record. [adr-003-cli]: adr-003-agent-consistent-human-first-cli.md +## Localization + +`src/locale_catalogues.rs` is the authoritative registry of shipped catalogues. +It sits at the crate root, not under `localization/`, because `localization` +builds its default localizer through `cli_localization`, and `cli_localization` +reads the registry; a registry inside `localization` would close that into a +module cycle. `localization::locales` re-exports it, so the older path still +resolves for callers. `define_locales!` declares the tags and embeds +`locales//messages.ftl` for each, so a tag without a catalogue on disk +fails to compile. Read the registry rather than writing a separate locale list; +the build audit, the `rerun-if-changed` directives, and the packaging smoke +test all do. `tests/locale_registry_tests.rs` is the deliberate exception: its +`EXPECTED_SHIPPED_TAGS` constant writes out every shipped tag by hand rather +than reading the registry, and asserts the registry matches it. A test that +reads the registry could only confirm the registry agrees with itself, so this +list stands as an independent oracle — adding or dropping a catalogue has to be +a conscious edit to it as well as to the registry. + +`Cargo.toml`'s `package.metadata.ortho_config.locales` is the one unavoidable +duplicate, because Cargo metadata cannot call into Rust. The build audit +compares it against the registry and fails on drift. + +Adding a locale therefore means: create `locales//messages.ftl` with every +declared key translated, add the tag to `define_locales!`, add it to the +`package.metadata.ortho_config.locales` array, and add it to +`EXPECTED_SHIPPED_TAGS` in `tests/locale_registry_tests.rs`. If the language +already ships a catalogue, add a `LANGUAGE_FALLBACKS` rule too, so the new tag +and the existing one resolve as intended rather than one of them capturing the +other. + +Each omission is caught, but not all by the same gate. A missing catalogue file +fails compilation, because `define_locales!` embeds it with `include_str!`. A +missing `Cargo.toml` entry fails the build-time audit. A missing +`EXPECTED_SHIPPED_TAGS` entry fails `make test` rather than the build, since +the oracle is a test: that is the cost of its independence, and the reason to +run the suite before assuming a locale is wired up. The `LANGUAGE_FALLBACKS` +rule is the exception with no gate at all — it is a judgement about which +variants are interchangeable, and nothing can infer it. + +Table 1: The locale API surface + +| Item | Purpose | +| ---------------------------------------- | --------------------------------------------------------------------------------------------- | +| `locales::SUPPORTED_LOCALES` | Every shipped catalogue, ordered by tag | +| `locales::catalogue(tag)` | Exact lookup; `None` when the tag ships no catalogue | +| `locales::resolve_catalogue(identifier)` | Exact match, then the fallback rules, then the sole catalogue for that language, then `en-US` | +| `locales::source_catalogue()` | The `en-US` catalogue every locale falls back to | +| `cli_localization::build_localizer(tag)` | The runtime entry point: resolves, then layers over `en-US` | + +Selection matches the exact BCP 47 tag first. A tag with no catalogue resolves +through the per-language rules in `LANGUAGE_FALLBACKS`, then the sole catalogue +for that language, then `en-US`. The rules keep variants that differ in +substance apart — `es-419` from `es-ES`, `pt-BR` from `pt-PT`, `zh-Hans` from +`zh-Hant` — so a new locale whose language already ships a catalogue needs a +rule rather than the unique-language step. The +[translator guide](translators-guide.md) states the same policy for +translators, and the users' guide lists the tags. + +Netsuke resolves the locale twice: `startup_localizer` before the configuration +merge, for help and usage errors, and `configure_runtime` afterwards, for +diagnostics and progress. Only the second sees a configuration file's `locale`, +because `--help` must render before Netsuke knows which configuration file to +read. + +### Startup diagnostics buffering + +Locale resolution happens before the command line is parsed, so a fallback +warning can be emitted before the effective diagnostic mode — human or JSON — +is known, yet the JSON diagnostic document is also written to stderr: an +eagerly emitted warning could corrupt it. `StartupWriter` in +`src/startup_tracing.rs` closes that window. It implements +`tracing_subscriber`'s `MakeWriter` and is installed by `init_tracing` in +`src/main.rs` before locale resolution runs, so every startup event is held +rather than written. The buffer is bounded at `MAX_BUFFERED_BYTES` (64 KiB): it +keeps the earliest bytes, appends a truncation marker once if the bound is +reached, and drops the remainder, so its size never depends on how much a run +emits. + +`settle_startup_diagnostics` in `src/main.rs` decides where the buffer goes +once the effective mode is known: human mode releases it to stderr, JSON mode +discards it so stderr carries only the diagnostic document. In +`run_with_args`, settlement happens after the JSON mode is resolved but before +the configuration merge, so a human-mode warning still precedes any +configuration processing. On the paths where `clap` calls `Error::exit` and +never returns — `parse_cli_or_exit` — settlement happens first, because +nothing after that call would otherwise run. + +Unit tests in `src/main_tests.rs` drive `startup_filter` and the real +`startup_localizer` to check the buffered warning and the level it is gated +by. `tests/startup_diagnostics_tests.rs` runs the built binary end to end, +including the configuration-driven JSON path, because the behaviour under test +spans the whole startup sequence and covers paths that terminate inside `clap` +before returning to `run_with_args`. + +**Cross-references:** `docs/netsuke-design.md` §8.4, for the rationale behind +buffering rather than gating output on the resolved mode. + +### Adding or changing messages + +Every user-facing string is a Fluent message keyed from +`src/localization/keys.rs`. Adding one means adding the constant, adding the +message to all 35 catalogues, and keeping its `{ $variables }` identical across +them: the build audit rejects a missing key, an orphaned key, or a variable set +that differs from `en-US`. The audit lives in `build_l10n_audit/`, split into +`keys.rs` and `scanner.rs` (the `define_keys!` scanner, with `byte_index.rs` +for its byte-position bookkeeping), `ftl.rs` (catalogues), `metadata.rs` (the +Cargo metadata), and `compare.rs` (the rules). Because build scripts are not +test targets, those modules are included by path from four test files: +`tests/build_l10n_keys_tests.rs` exercises the `define_keys!` scanner +(`keys.rs`, `scanner.rs`, `byte_index.rs`); `tests/build_l10n_parser_tests.rs` +exercises the catalogue and metadata parsers (`ftl.rs`, `metadata.rs`); +`tests/build_l10n_audit_rules_tests.rs` exercises the comparison rules +(`compare.rs`, alongside `ftl.rs`); and `tests/build_l10n_audit_tests.rs` runs +the orchestration end to end, both over the checked-in tree and over +deliberately corrupted copies of it. + ## Graph view projection and renderer adapters The `graph` subcommand renders the build dependency graph in-process. Its @@ -647,7 +763,7 @@ and `-Clink-arg=-fuse-ld=mold`. ### Testing the tooling -Five suites cover the tooling's observable behaviour. All are hermetic — no +Six suites cover the tooling's observable behaviour. All are hermetic — no network, and no real `mold`, `rustup`, or Cargo — so they run as part of `make test` on any Linux host. @@ -1050,8 +1166,10 @@ the configured Dependabot directory patterns. `tests/packaging_smoke_tests.rs` runs `cargo publish --dry-run` to verify the packaged crate builds successfully for release. It then uses `cargo package --list` to confirm that the packaged manifest retains -build-script sources, including `build_l10n_audit.rs`, and rejects stale -`ninja_env/` paths. +build-script sources, including the `build_l10n_audit/` modules, and rejects +stale `ninja_env/` paths. It also asserts that every catalogue named by the +locale registry ships in the package, so adding a locale cannot silently omit +its `messages.ftl` from a release. ### Temporary executable test helpers @@ -1455,6 +1573,27 @@ Three dispositions are in use: Scope an expectation as tightly as the site allows — a function where one call is involved, a module only where the whole file is pending migration. +### `LocaleLocalizer` + +`test_support::localizer::locale_localizer` installs a test locale under +`LOCALIZER_TEST_LOCK`, the same lock the `en_localizer` fixture uses, so tests +that mutate the process-global localizer run in sequence rather than racing. + +Dropping the returned `LocaleLocalizer` restores the previously installed +localizer and *then* releases the lock, in that order. The ordering is the +field declaration order, since Rust drops fields in the order they are +declared, and it is the whole point of the type: releasing first would admit +another test into the window between the two, where its localizer would be +installed and then overwritten by the restore. + +That ordering has no behavioural signature under normal scheduling — a waiting +thread almost never lands inside a window a few instructions wide — so a +contention test cannot detect the wrong order. `RestoreProbe` wraps the +localizer guard and records, at the instant restoration begins, whether the +lock is still held; `try_lock` from the owning thread returns `WouldBlock`, so +"blocked" means the bundle still holds it. Reverting the field order turns that +assertion red deterministically. + ### `EnvLock` `test_support::env_lock::EnvLock` is a global mutex that serializes all @@ -1596,17 +1735,17 @@ Do **not** call `std::env::set_var` directly in BDD steps — use ### `tracing_capture` -Production tracing has one process-wide subscriber, installed by `init_tracing` -in `src/main.rs` with a reloadable filter initially set to `OFF`. Early -configuration resolution therefore cannot write selector events before the -effective JSON mode is known. On success, `resolve_json_mode_or_exit` calls -`set_tracing_filter` with the resolved mode: JSON stays `OFF`, while human mode -enables `TRACE` for `--verbose` or `ERROR` otherwise. Full human-mode merging -repeats discovery after the filter is enabled, so its selector events remain -available. If early resolution fails, human mode enables its fallback filter -and replays resolution to retain bounded failure diagnostics; JSON mode leaves -the filter off and discards them. No library module installs a global -subscriber. +Production tracing has one process-wide subscriber, installed by +`init_tracing` in `src/main.rs` with a reloadable filter starting at `WARN`. +Events are written through `StartupWriter`, which buffers startup tracing +until the effective diagnostic mode is known — no startup tracing reaches +stdout. The buffer is bounded (64 KiB), with a truncation policy documented +in the "Startup diagnostics buffering" subsection above. +`settle_startup_diagnostics` then releases the buffer to stderr in human +mode, or discards it in JSON mode. Once the mode is resolved, +`set_tracing_filter` adjusts the level to the one `startup_filter` chooses +for the mode, with a fallback filter on the paths where resolution itself +fails. No library module installs a global subscriber. Tests use a separate capture boundary: diff --git a/docs/execplans/3-7-3-translator-tooling-and-documentation.md b/docs/execplans/3-7-3-translator-tooling-and-documentation.md index e9d6261da..4ae7849b4 100644 --- a/docs/execplans/3-7-3-translator-tooling-and-documentation.md +++ b/docs/execplans/3-7-3-translator-tooling-and-documentation.md @@ -8,6 +8,13 @@ Status: DONE No `PLANS.md` file exists in this repository. +> **Superseded in part.** This plan records the state of localization when it +> was executed, when Netsuke shipped two catalogues. Issue #466 replaced that +> arrangement with a registry model: `src/locale_catalogues.rs` declares every +> shipped tag and embeds its catalogue, and Netsuke now ships 35 of them. The +> references below have been corrected to name the current modules and model, +> but the plan's sequencing and decisions are left as executed. + ## Purpose / big picture Roadmap item 3.7.3 requires providing translator tooling and documentation @@ -16,8 +23,11 @@ localization smoke tests cover at least one secondary locale. The existing infrastructure already includes: -- Fluent localization with en-US and es-ES locales (318 messages each) -- Compile-time key audit (`build_l10n_audit.rs`) validating key parity +- Fluent localization, at the time of this plan covering en-US and es-ES + (now 35 catalogues, declared by the registry in `src/locale_catalogues.rs`) +- A build-time audit (`build_l10n_audit/`) validating that every catalogue + declares exactly the keys `define_keys!` declares, and that each shared + message interpolates the same Fluent variables as the `en-US` source - Localization smoke tests in `tests/localization_tests.rs` confirming es-ES resolves Spanish and fr-FR falls back to English @@ -100,11 +110,14 @@ Success is observable by: ## Decision log - Decision: Documentation-first approach without automated variable audit. - Rationale: The existing compile-time key audit in `build_l10n_audit.rs` - already validates key parity. Adding automated variable consistency checking - would expand scope significantly. Manual variable documentation in the - translator guide is sufficient for this milestone. Date/Author: 2026-01-31 - (Plan) + Rationale: The existing build-time key audit in `build_l10n_audit/` already + validates key parity. Adding automated variable consistency checking would + expand scope significantly. Manual variable documentation in the translator + guide is sufficient for this milestone. Date/Author: 2026-01-31 (Plan) + + Superseded: the audit now also validates Fluent interpolation-variable parity + against `en-US`, which this decision had left out of scope. The original + scoping stands as recorded; the contract it describes has since widened. - Decision: Keep plural form examples as documentation, despite selection not working. Rationale: The FTL syntax is valid and demonstrates correct Fluent @@ -137,11 +150,13 @@ numeric types for proper plural form support. Localization is implemented via: -- `locales/en-US/messages.ftl` - English source messages (318 keys) -- `locales/es-ES/messages.ftl` - Spanish translations (318 keys) +- `locales/en-US/messages.ftl` - English source messages +- `locales/es-ES/messages.ftl` - Spanish translations + (one catalogue per registry tag; 35 in the current tree) - `src/localization/keys.rs` - Compile-time key constants via `define_keys!` - `src/cli_localization.rs` - Builds Fluent localizers with fallback chains -- `build_l10n_audit.rs` - Compile-time audit ensuring key parity +- `build_l10n_audit/` - Build-time audit ensuring key parity and Fluent + interpolation-variable parity against `en-US` Message keys use hierarchical dot-notation (e.g., `cli.flag.file.help`, `stdlib.fetch.url_invalid`) organized by domain: @@ -318,4 +333,4 @@ No new dependencies required. Uses existing: | `tests/localization_tests.rs` | Add plural tests | | `docs/users-guide.md` | Add guide reference | | `docs/roadmap.md` | Mark 3.7.3 done | -| `build_l10n_audit.rs` | Existing audit (no changes) | +| `build_l10n_audit/` | Existing audit (no changes) | diff --git a/docs/netsuke-design.md b/docs/netsuke-design.md index d2d80526a..29943da6e 100644 --- a/docs/netsuke-design.md +++ b/docs/netsuke-design.md @@ -2453,26 +2453,74 @@ output: each invocation emits one versioned result document on success or one versioned diagnostic document on failure. CLI help and clap errors are localized via Fluent resources; locale resolution -is handled in `src/locale_resolution.rs` with the precedence `--locale` -> -`NETSUKE_LOCALE` -> configuration `locale` -> system default. System locale -strings are normalized by stripping encoding suffixes (such as `.UTF-8`), -removing variant suffixes (such as `@latin`), and replacing underscores with -hyphens before validation. English plus Spanish catalogues ship in `locales/`; -unsupported locales fall back to `en-US`. Runtime diagnostics (for example -manifest parsing, stdlib template errors, and runner failures) use the same -Fluent localizer so the locale selection is consistent across user-facing -output. A build-time audit in `build.rs` validates that all referenced Fluent -message keys exist in the bundled catalogues, ensuring missing strings fail CI -before release. CLI execution and dispatch live in `src/runner.rs`, keeping -`main.rs` focused on parsing. Process management, Ninja invocation, argument -redaction, and the temporary file helpers reside in `src/runner/process.rs`, -allowing the runner entry point to delegate low-level concerns. The working -directory flag mirrors Ninja's `-C` option but is resolved internally: Netsuke -runs Ninja with a configured working directory and resolves relative output -paths (for example `generate --output`) under the same directory so behaviour -matches a real directory change. Error scenarios are validated using clap's -`ErrorKind` enumeration in unit tests and via rstest-bdd behavioural -steps/scenarios. +is handled in `src/locale_resolution.rs` in two phases. Before the +configuration merge, `startup_localizer` (`src/main.rs`) resolves the locale +used for help and clap errors, with the precedence `--locale` -> +`NETSUKE_LOCALE` -> system locale -> `en-US`; configuration cannot take part +here because it has not been read yet. After the merge, `configure_runtime` +resolves the locale again, this time for runtime diagnostics and progress, +and this phase can honour a configuration file's `locale` setting. System +locale strings are normalized by stripping encoding suffixes (such as +`.UTF-8`), removing variant suffixes (such as `@latin`), and replacing +underscores with hyphens before validation. + +Startup diagnostics are buffered rather than written. The locale is resolved +before the command line is parsed, so a fallback can be reported before the +effective diagnostic mode is known, and the JSON diagnostic document is written +to stderr — an eagerly emitted warning could corrupt it. `StartupWriter` in +`src/startup_tracing.rs` therefore holds startup tracing until the mode is +settled. `settle_startup_diagnostics` in `src/main.rs` then releases the buffer +to stderr in human mode, or discards it in JSON mode so that stderr carries a +single diagnostic document. Settlement happens after the JSON mode is resolved +but before the configuration merge, so a human-mode warning still precedes any +configuration processing, and on the paths where clap terminates the process it +happens before that exit. The buffer is bounded: it keeps the earliest bytes, +appends a truncation marker once, and drops the remainder, so its size never +depends on how much a run emits. + +`src/locale_catalogues.rs` is the authoritative registry of shipped catalogues. +A `define_locales!` macro embeds `locales//messages.ftl` for each declared +tag, so a registry entry without a catalogue fails to compile. Every other +surface reads that registry rather than repeating the list: the build-time +audit, the `cargo:rerun-if-changed` directives, and the packaging smoke test. +`Cargo.toml`'s `package.metadata.ortho_config.locales` array is a place the +list is necessarily duplicated, because Cargo metadata cannot call into Rust; +the build audit therefore compares it against the registry and fails on drift. +`tests/locale_registry_tests.rs` is the deliberate exception: its +`EXPECTED_SHIPPED_TAGS` constant writes out the shipped locale set by hand +rather than deriving it from the registry, because a test that reads the +registry and asserts the registry against itself can only confirm the registry +agrees with itself — it cannot catch an accidental addition or removal. That +list is therefore an independent statement of intent, kept in step with the +registry by deliberate edit. + +Catalogue selection matches the exact BCP 47 tag first. When no catalogue +carries that tag, resolution consults the per-language fallback rules recorded +in the registry, then the sole catalogue for that language, and finally +`en-US`. The rules exist so that variants which differ in substance stay +distinct rather than collapsing onto a generic language catalogue: `es-419` +serves Latin American regions while `es-ES` serves Spain, `pt-BR` and `pt-PT` +never share, and `zh-Hans` and `zh-Hant` are selected by script or by the +script a region conventionally uses. English outside the United States prefers +the `en-GB` copy, and the bare `no` macrolanguage tag resolves to `nb`. The +[translator guide](translators-guide.md) states the same policy for translators. + +Runtime diagnostics (for example manifest parsing, stdlib template errors, and +runner failures) use the same Fluent localizer so the locale selection is +consistent across user-facing output. The build-time audit in +`build_l10n_audit/` validates every declared locale: it rejects catalogues that +omit a declared key, carry a key beyond the declared set, or interpolate a +different set of variables from the English source catalogue. Missing or +drifted strings therefore fail CI before release. CLI execution and dispatch +live in `src/runner.rs`, keeping `main.rs` focused on parsing. Process +management, Ninja invocation, argument redaction, and the temporary file +helpers reside in `src/runner/process.rs`, allowing the runner entry point to +delegate low-level concerns. The working directory flag mirrors Ninja's `-C` +option but is resolved internally: Netsuke runs Ninja with a configured working +directory and resolves relative output paths (for example `generate --output`) +under the same directory so behaviour matches a real directory change. Error +scenarios are validated using clap's `ErrorKind` enumeration in unit tests and +via rstest-bdd behavioural steps/scenarios. Real-time stage reporting now uses a six-stage model in `src/status.rs` backed by `indicatif::MultiProgress` for standard terminals. The reporter keeps one @@ -2525,25 +2573,39 @@ subcommands, configuration layering, and JSON diagnostics so the guide stays synchronized with runtime behaviour rather than drifting behind it. For screen readers: The following flowchart shows how the build script audits -localization keys against English and Spanish Fluent bundles. +every registered locale's Fluent catalogue. It first checks that the Cargo +metadata matches the locale registry; a mismatch is reported on its own and +fails the build immediately, without examining any catalogue. Otherwise it +reads the declared keys and the English source catalogue, then loops over each +registered locale comparing keys and interpolation variables, collecting that +locale's findings before moving to the next. Once every locale has been +examined, any collected finding fails the build. ```mermaid flowchart TD - A_Start["Start build.rs"] --> B_ReadKeys - B_ReadKeys["extract_key_constants
from src/localization/keys.rs"] --> C_ReadEn - C_ReadEn["extract_ftl_keys
from locales/en-US/messages.ftl"] --> D_ReadEs - D_ReadEs["extract_ftl_keys
from locales/es-ES/messages.ftl"] --> E_Compare - - E_Compare["Compute differences
between declared and en-US/es-ES keys"] --> F_CheckMissing - - F_CheckMissing{"Any missing
keys?"} -->|No| G_Success["Audit passes
continue build"] - F_CheckMissing -->|Yes| H_Error["Emit error message
with missing keys per locale
and fail build"] - - H_Error --> I_End["Build script returns Err"] - G_Success --> I_End + A_Start["Start build.rs"] --> B_Metadata + B_Metadata{"Cargo.toml locales
match the registry?"} -->|No| N_Drift + N_Drift["Report the metadata drift"] --> M_Fail + B_Metadata -->|Yes| C_ReadKeys + C_ReadKeys["extract_key_constants
from src/localization/keys.rs"] --> D_ReadSource + D_ReadSource["parse_catalogue
from locales/en-US/messages.ftl"] --> E_Loop + + E_Loop["For each locale in
SUPPORTED_LOCALES"] --> F_Parse + F_Parse["parse_catalogue
from locales/<tag>/messages.ftl"] --> G_Compare + G_Compare["Compare keys and
interpolation variables
against the source"] --> I_Check + + I_Check{"Missing, orphaned,
or mismatched?"} -->|No| J_Next + I_Check -->|Yes| H_Error["Collect findings
for this locale"] + H_Error --> J_Next + + J_Next{"More locales?"} -->|Yes| E_Loop + J_Next -->|No| K_Verdict + + K_Verdict{"Any findings?"} -->|No| L_Success["Audit passes
continue build"] + K_Verdict -->|Yes| M_Fail["Report the failures
and fail the build"] ``` -Figure: Build script localization audit flow for Fluent key validation. +Figure: Build script localization audit flow across every registered locale. The Ninja executable may be overridden via the `NETSUKE_NINJA` environment variable. For example, `NETSUKE_NINJA=/opt/ninja/bin/ninja netsuke build` diff --git a/docs/polonius.md b/docs/polonius.md index 93578d36f..734a7daa5 100644 --- a/docs/polonius.md +++ b/docs/polonius.md @@ -82,9 +82,13 @@ Scanner suspects that turned out not to be NLL residue: needs no Polonius caveat. - `src/cli/merge.rs` — clones construct the resolved `Cli` from borrowed layers; owned construction of a new value, not clone-modify-writeback. -- `build_l10n_audit.rs` — `find_matching_brace` and `find_raw_string_end` - return byte offsets into source text; the index is the result (a data id), - not a borrow dodge. +- `build_l10n_audit/` — the audit is split by input kind: `keys.rs` reads the + `define_keys!` macro, `scanner.rs` holds the byte-level scanner it drives, + `ftl.rs` parses catalogues, `metadata.rs` reads the Cargo metadata, and + `compare.rs` holds the comparison rules. The scanner works in byte positions + into borrowed source text — `find_matching_brace` in `keys.rs` and + `find_raw_string_end` in `scanner.rs` both return byte offsets. The index is + the result (a data id), not a borrow dodge. - Test-suite `drop()` calls (environment guards, HTTP fixture teardown) are semantic Drop effects, not borrow appeasement. diff --git a/docs/repository-layout.md b/docs/repository-layout.md index f8b3e0577..2f2c61884 100644 --- a/docs/repository-layout.md +++ b/docs/repository-layout.md @@ -70,8 +70,11 @@ output and some leaf files so the long-lived structure remains visible. - `examples/`: Example Netsuke manifests and minimal runnable sample projects. - `installer/`: Installer packaging assets and platform-specific packaging definitions. -- `locales/`: Fluent localization catalogues for supported user-interface - languages. +- `locales/`: Fluent localization catalogues, one `/messages.ftl` per + supported locale tag, so regional and script variants such as `es-419`, + `pt-BR`, and `zh-Hant` each keep their own directory. The authoritative list + of tags lives in `src/locale_catalogues.rs`; see the + [translator guide](translators-guide.md). - `scripts/`: Shell and helper scripts used by quality gates, release help generation, packaging, and formal checks. - `src/`: Main Netsuke Rust crate source code. diff --git a/docs/sample-netsuke.toml b/docs/sample-netsuke.toml index 95fc7d446..1d1fc9e93 100644 --- a/docs/sample-netsuke.toml +++ b/docs/sample-netsuke.toml @@ -15,7 +15,12 @@ # Enable verbose diagnostics and timing summaries. # verbose = true -# Locale for CLI messages, for example `en-US` or `es-ES`. +# Locale for CLI messages, as a BCP 47 tag, for example `en-US`, `pt-BR` or +# `zh-Hant`. The exact tag is matched first, then the registry's per-language +# script and region rules, then the sole catalogue for that language if it has +# only one, so `fr-CA` uses `fr`, and finally `en-US`. Variants that differ in +# substance stay distinct: `pt-BR` never yields European Portuguese. See the +# users' guide for the full list. # locale = "en-US" # Emit one versioned JSON document: a result on success or diagnostic on failure. diff --git a/docs/translators-guide.md b/docs/translators-guide.md index 0b4b6a681..a6d476925 100644 --- a/docs/translators-guide.md +++ b/docs/translators-guide.md @@ -9,12 +9,17 @@ Netsuke uses [Project Fluent](https://projectfluent.org/) for localization. Fluent is a modern localization system designed to handle the complexities of natural language whilst keeping translations simple and readable. -**Current locales:** +**Locale precedence** (highest to lowest). Netsuke resolves twice because help +and usage errors are rendered before any configuration file is read. -- `en-US` - English (United States) - source locale -- `es-ES` - Spanish (Spain) - reference translation +At startup, for help, usage, and command-line validation errors: -**Locale precedence** (highest to lowest): +1. `--locale` command-line flag +2. `NETSUKE_LOCALE` environment variable +3. System default locale +4. Fallback to `en-US` + +After the configuration merge, for diagnostics, progress, and status output: 1. `--locale` command-line flag 2. `NETSUKE_LOCALE` environment variable @@ -22,16 +27,93 @@ natural language whilst keeping translations simple and readable. 4. System default locale 5. Fallback to `en-US` -## 2. File structure - -Translation files are located in the `locales/` directory: - -```text +`startup_localizer` in `src/main.rs` performs the first and `configure_runtime` +the second; both resolve through `src/locale_resolution.rs`. + +`en-US` is the source locale: it defines the key set every other catalogue must +match, and it renders any message a translation has not yet covered. + +### Shipped locales + +Table 1: Locales Netsuke ships, by script family + +| Script family | Tags | +| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Latin | `cs`, `cy`, `da`, `de`, `en-GB`, `en-US`, `es-419`, `es-ES`, `fi`, `fr`, `gd`, `hu`, `id`, `it`, `nb`, `nl`, `pl`, `pt-BR`, `pt-PT`, `ro`, `sv`, `tr`, `vi` | +| Cyrillic | `ru`, `uk` | +| Greek | `el` | +| Right-to-left | `ar`, `fa`, `he` | +| Indic | `hi` | +| Thai | `th` | +| CJK | `ja`, `ko`, `zh-Hans`, `zh-Hant` | + +## 2. The locale registry + +`src/locale_catalogues.rs` owns the list of locales. Its `define_locales!` +macro both declares the supported tags and embeds each catalogue, so a tag +without a catalogue on disk fails to compile. Everything downstream reads the +registry rather than keeping its own list: the build-time audit, the +`cargo:rerun-if-changed` directives, the packaging smoke test, and the tests — +with two deliberate exceptions: the `locales` array in `Cargo.toml`'s +`[package.metadata.ortho_config]` table, and `EXPECTED_SHIPPED_TAGS` in +`tests/locale_registry_tests.rs`, both described below. + +Two places name the locale list independently of the registry, for different +reasons. `package.metadata.ortho_config.locales` in `Cargo.toml` duplicates it +because Cargo metadata cannot call into Rust; the build audit compares the two +and fails the build if they drift. `EXPECTED_SHIPPED_TAGS` in +`tests/locale_registry_tests.rs` duplicates it deliberately, as an independent +oracle: a test that only read the registry back could never catch a locale +added or dropped by accident, since it would just be confirming the registry +agrees with itself. + +Adding a locale means creating `locales//messages.ftl`, adding the tag to +`define_locales!` in `src/locale_catalogues.rs`, adding it to that `Cargo.toml` +array, and adding it to `EXPECTED_SHIPPED_TAGS`. When the language already +ships one or more catalogues — currently `en`, `es`, `pt`, and `zh` — it also +means extending its `LANGUAGE_FALLBACKS` rule so every relevant region and +script, old and new, still resolves deterministically to exactly one variant. + +### Fallback policy + +Selection matches the exact BCP 47 tag first. A tag with no catalogue of its +own resolves in this order: + +1. A script or region rule for that language, where the registry declares one. +2. The only catalogue for that language, so `fr-CA` uses `fr`. +3. `en-US`. + +Table 2: Deliberate per-language fallback rules + +| Language | Rule | +| -------- | ------------------------------------------------------------------------------------------------- | +| `en` | `en-US` for the bare tag and the United States; `en-GB` for every other region | +| `es` | `es-ES` for the bare tag and Spain; `es-419` for every other region | +| `pt` | `pt-BR` for Brazil; `pt-PT` for the bare tag and every other region | +| `zh` | Script wins; otherwise `zh-Hans` for the bare tag, CN, SG and MY, and `zh-Hant` for TW, HK and MO | +| `no` | `nb`, the Bokmål catalogue | + +These rules exist so that variants which differ in substance stay distinct. +`es-419` is not a synonym for `es-ES`, `pt-BR` is not a synonym for `pt-PT`, and +`zh-Hans` is not a synonym for `zh-Hant`; collapsing any of these onto a +generic language catalogue would ship the wrong copy. When adding a locale +whose language already ships a catalogue, add a rule to the registry rather +than relying on the unique-language step. + +## 3. File structure + +Translation files are located in the `locales/` directory, one directory per +tag: + +```plaintext locales/ ├── en-US/ │ └── messages.ftl -└── es-ES/ - └── messages.ftl +├── es-419/ +│ └── messages.ftl +├── es-ES/ +│ └── messages.ftl +└── … ``` Each locale has a single `messages.ftl` file containing all translations. @@ -56,11 +138,11 @@ greeting = Hello, { $name }! - Lines starting with `.` are attributes (sub-messages) - Lines starting with `-` are terms (reusable fragments, not referenced in code) -## 3. Message key conventions +## 4. Message key conventions Netsuke uses hierarchical dot-notation for message keys, organized by domain. -Table 1: Message key domains and their purposes +Table 3: Message key domains and their purposes | Domain | Purpose | Example | | ------------------ | ---------------------------------- | ----------------------------- | @@ -81,7 +163,7 @@ The corresponding Rust constants are defined in `src/localization/keys.rs` using UPPER_SNAKE_CASE (e.g., `CLI_FLAG_FILE_HELP` maps to `cli.flag.file.help`). -## 4. Variable usage +## 5. Variable usage Variables are placeholders replaced with dynamic values at runtime. @@ -97,7 +179,7 @@ range-error = Value { $value } must be between { $min } and { $max }. ### Variable types -Table 2: Variable types used in Fluent messages +Table 4: Variable types used in Fluent messages | Type | Description | Example | | ------ | ---------------------------------- | ----------------------------- | @@ -140,7 +222,7 @@ Table 2: Variable types used in Fluent messages - `$limit` - Size limit in bytes - `$mode`, `$stream` - Output configuration -## 5. Plural forms +## 6. Plural forms Fluent uses Common Locale Data Repository (CLDR) plural rules to handle grammatical number. Different languages have different plural categories. @@ -183,16 +265,40 @@ example.errors_found = { $count -> ### CLDR plural categories by language -Table 3: CLDR plural categories for common languages - -| Language | Categories | -| -------- | -------------------------------------------- | -| English | `one`, `other` | -| Spanish | `one`, `other` | -| French | `one`, `other` | -| Russian | `one`, `few`, `many`, `other` | -| Arabic | `zero`, `one`, `two`, `few`, `many`, `other` | -| Japanese | `other` (no grammatical plural) | +Table 5: CLDR plural categories by shipped locale + +| Categories | Locales | +| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| `other` | `id`, `ja`, `ko`, `th`, `vi`, `zh-Hans`, `zh-Hant` | +| `one`, `other` | `da`, `de`, `el`, `en-GB`, `en-US`, `es-419`, `es-ES`, `fa`, `fi`, `fr`, `hi`, `hu`, `it`, `nb`, `nl`, `pt-BR`, `pt-PT`, `sv`, `tr` | +| `one`, `few`, `other` | `ro` | +| `one`, `few`, `many`, `other` | `cs`, `pl`, `ru`, `uk` | +| `one`, `two`, `few`, `other` | `gd` | +| `one`, `two`, `many`, `other` | `he` | +| `zero`, `one`, `two`, `few`, `many`, `other` | `ar`, `cy` | + +A locale that lists a category must spell out its own wording for that variant. +A test in `tests/locale_catalogue_tests.rs` asserts these category sets for +every shipped locale, so dropping Polish `few` or Welsh `two` fails the suite +rather than quietly losing a form. That test carries the same table, and a +second test fails if any registry locale is missing from it. + +The categories are the ones the `intl_pluralrules` crate implements — the +plural-rules engine Fluent consults when selecting a variant — and they can lag +a newer CLDR release. + +CLDR also gives French, Spanish, Italian, and Portuguese a `many` category, at +million-scale values and in compact-number forms. That is a property of CLDR, +not of Netsuke: whether Netsuke ever selects it depends on the counts its +messages carry, and none of the shipped messages counts in millions. + +Note that `one` does not always mean "exactly one": in French it also covers +zero, and in Hindi likewise. Nor does listing `one` imply the wording differs +from `other` — Hungarian and Turkish keep the noun singular after any numeral, +so both variants read alike, but CLDR defines `one` for them and the catalogue +must offer it. Where a language prefers a distinct phrase for none at all, use +an explicit `[0]` variant, as the shipped catalogues do for +`example.errors_found`. Consult the [CLDR plural rules](https://cldr.unicode.org/index/cldr-spec/plural-rules) for @@ -209,94 +315,161 @@ for CLDR category selection. FTL files include plural form examples demonstrating correct Fluent syntax for future compatibility when numeric argument support is added. -## 6. Adding a new locale +## 7. Adding a new locale -To add support for a new language (e.g., French `fr-FR`): +A locale tag need not introduce a whole new language; it can also be a +region or script variant of a language Netsuke already ships, such as +`pt-BR` alongside `pt-PT`, since the registry resolves by tag rather than by +language. To add support for a new locale tag (for example Icelandic, `is`): -### Step 1: Create the locale directory +### Step 1: Start from the source catalogue ```sh -mkdir -p locales/fr-FR +mkdir -p locales/is +cp locales/en-US/messages.ftl locales/is/messages.ftl ``` -### Step 2: Copy the English source file - -```sh -cp locales/en-US/messages.ftl locales/fr-FR/messages.ftl -``` +The copy is a starting scaffold, not a deliverable. A catalogue that still +carries English values is not a translation, and a test rejects one. -### Step 3: Translate messages +### Step 2: Translate the messages -Edit `locales/fr-FR/messages.ftl` and translate each message. Keep the same -keys; only change the values. +Edit `locales/is/messages.ftl` and translate each value. Keep every key, keep +each message's `{ $variables }` exactly as the English source has them, and +translate the section comments so the next translator has the same context. ```ftl # Before (English): cli.about = Netsuke compiles YAML + Jinja manifests into Ninja build plans. -# After (French): -cli.about = Netsuke compile les manifestes YAML + Jinja en plans Ninja. +# After (Icelandic): +cli.about = Netsuke þýðir YAML + Jinja lýsingarskrár í Ninja-byggingaráætlanir. ``` -### Step 4: Update the localizer builder - -Edit `src/cli_localization.rs` to include the new locale: +Leave Netsuke's own identifiers untranslated — users type them. That covers +`foreach`, `when`, `vars`, `cwd_mode`, `with_suffix`, `group_by`, the +`netsuke::jinja::*` diagnostic tags, the literal option values (`auto`, +`always`, `never`, `on`, `off`) and the shell fragment `ninja -t clean`. -1. Add an embedded resource constant: +### Step 3: Register the locale - ```rust - const NETSUKE_FR_FR: &str = include_str!("../locales/fr-FR/messages.ftl"); - ``` +Add the tag to the three lists that name it: -2. Update `build_localizer()` to handle the new locale tag. +1. `define_locales!` in `src/locale_catalogues.rs`, in tag order. +2. `package.metadata.ortho_config.locales` in `Cargo.toml`, in the same order. +3. `EXPECTED_SHIPPED_TAGS` in `tests/locale_registry_tests.rs`, the + independent test oracle, in the same order. -### Step 5: Run the build +If the language already ships a catalogue — a new Spanish or Chinese variant, +say — also add or extend its entry in `LANGUAGE_FALLBACKS` so requests route to +the right variant rather than falling through to the first match. -The compile-time audit will verify all keys are present: +### Step 4: Build ```sh cargo build ``` -If any keys are missing or orphaned, the build will fail with a detailed error. +The compile-time audit verifies that the locale registry and Cargo.toml's +metadata agree, and that the catalogue's keys and interpolation variables +match the source. -### Step 6: Test the locale +### Step 5: Test the locale ```sh -cargo run -- --locale fr-FR --help +make test +cargo run -- --locale is --help ``` -Verify the output appears in French. +`make test` also validates the tag against `EXPECTED_SHIPPED_TAGS`, the +independent oracle in `tests/locale_registry_tests.rs`. Verify the output +appears in Icelandic. + +## 8. Right-to-left locales + +Arabic, Hebrew, and Persian ship right-to-left catalogues. Fluent already wraps +interpolated values in bidi isolation controls, so `{ $path }` needs no special +handling. What does need care is the *first* character of a message: a value +that opens with a Latin word, a bracket, or a placeable lets that token decide +the paragraph direction, which flips the whole line in a terminal. + +Prefix such values with U+200F RIGHT-TO-LEFT MARK: + +```ftl +# The leading Latin word would otherwise set the direction. +manifest.yaml.label = ‏YAML غير صالح +``` + +A template assembled only from placeables and punctuation needs the mark just +as much, and less obviously. Because Fluent isolates every interpolated value, +`[{ $state }] { $label }` carries no strong character of its own at all, so its +paragraph direction falls back to left-to-right and the brackets land on the +wrong side: + +```ftl +# No strong character outside the isolates, so the direction must be stated. +status.stage.summary = ‏[{ $state }] { $label } +``` + +The same applies to each variant of a `select` expression: whichever variant +Fluent picks becomes the entire rendered string, so a variant that opens with +`{ $count }` needs its own mark. + +A test in `tests/locale_catalogue_tests.rs` enforces this. Every rendered +fragment of a right-to-left catalogue — each message value and each `select` +variant — must begin with either a right-to-left character or U+200F. The +exceptions are listed explicitly in that test: `cli.usage`, the `stdout` and +`stderr` stream names, the `netsuke::jinja::which::args` diagnostic, and the +`semantic.prefix.rendered` composition template. Each is a technical token or +an all-Latin line, where pinning the direction would push a Latin identifier to +the wrong edge of the terminal. -## 7. Quality checklist +## 9. Quality checklist Before submitting translations, verify: - [ ] All message keys from `en-US/messages.ftl` are present - [ ] No extra (orphaned) keys exist - [ ] All variables match the English source (same names, same count) -- [ ] Plural forms use correct CLDR categories for the target language +- [ ] Plural forms use the CLDR categories in Table 5 for the target language +- [ ] Netsuke identifiers and literal option values are untranslated +- [ ] Right-to-left catalogues carry the direction marks described in §8 - [ ] Comments are translated or preserved for context - [ ] The build passes (`cargo build`) +- [ ] The tests pass (`make test`) - [ ] The locale renders correctly (`netsuke --locale --help`) -## 8. Compile-time validation +## 10. Compile-time validation -Netsuke validates translations at compile time via `build_l10n_audit.rs`: +Netsuke validates every registered locale at compile time via +`build_l10n_audit/`: +- **Metadata drift**: `Cargo.toml`'s locale list disagrees with the registry - **Missing keys**: Keys in `keys.rs` but not in the FTL file - **Orphaned keys**: Keys in the FTL file but not in `keys.rs` +- **Variable mismatches**: A message interpolating different variables from the + English source — a dropped `{ $path }` or a stray `{ $name }` -Both conditions cause the build to fail with a clear error message listing the -problematic keys. +Catalogue findings — missing keys, orphaned keys, and variable mismatches — +fail the build with an error naming the affected locale and the keys +concerned. Metadata drift fails the build with a different message, one that +prints the two disagreeing lists side by side: the registry's tags and +`Cargo.toml`'s. -## 9. Testing translations +## 11. Testing translations Localization is tested via: -- **Unit tests** (`tests/localization_tests.rs`): Verify message rendering -- **Smoke tests**: Confirm secondary locales resolve correctly -- **Fallback tests**: Verify unsupported locales fall back to English +- **Rendering tests** (`tests/localization_tests.rs`): every registered locale + renders and interpolates its arguments; non-Latin scripts and right-to-left + direction marks survive to the rendered string +- **Registry tests** (`tests/locale_registry_tests.rs`): each shipped tag + resolves to its own catalogue, each documented fallback rule holds, and + unsupported or unparsable tags fall back to `en-US` +- **Catalogue tests** (`tests/locale_catalogue_tests.rs`): CLDR plural + categories per language, the right-to-left direction policy, untranslated + Netsuke identifiers, and the rule that a translation is not a copy of the + English source Run tests with: @@ -304,7 +477,7 @@ Run tests with: make test ``` -## 10. Resources +## 12. Resources - [Project Fluent](https://projectfluent.org/) - Fluent documentation - [Fluent Syntax Guide](https://projectfluent.org/fluent/guide/) - FTL syntax diff --git a/docs/users-guide.md b/docs/users-guide.md index 78d071339..80431ace0 100644 --- a/docs/users-guide.md +++ b/docs/users-guide.md @@ -70,7 +70,7 @@ licence files. Installer packages do not have checksum sidecars in v0.1.0. Windows PowerShell help files are published beside each MSI as sidecar artefacts rather than embedded in the installer. -To install the current source checkout with Cargo. The clone supplies both the +Install the current source checkout with Cargo. The clone supplies both the pinned nightly toolchain and `RUSTFLAGS=-Zpolonius=next`, so neither is given here — unlike the registry install above, which runs outside a checkout: @@ -493,6 +493,69 @@ Important global options include: Run `netsuke --help` or `netsuke --help` for the complete current surface. +### Choose a language with `--locale` + +Netsuke's help text, validation errors, progress labels, and runtime +diagnostics are translated. The locale is chosen by the first source that +yields a valid BCP 47 tag, and which sources are available depends on when the +message is rendered. + +Help, usage, and command-line validation errors are produced before any +configuration file is read, so they use the `--locale` flag, then +`NETSUKE_LOCALE`, then the system default, then `en-US`. Diagnostics, progress, +and status output are rendered after the configuration merge, so they consult +the configuration file's `locale` setting as well, between `NETSUKE_LOCALE` and +the system default. + +System values are normalized first, so `en_GB.UTF-8` is understood as `en-GB`. + +Table 1: Locales Netsuke ships + +| Tag | Language | Tag | Language | +| -------- | ------------------------ | --------- | --------------------- | +| `ar` | Arabic | `it` | Italian | +| `cs` | Czech | `ja` | Japanese | +| `cy` | Welsh | `ko` | Korean | +| `da` | Danish | `nb` | Norwegian Bokmål | +| `de` | German | `nl` | Dutch | +| `el` | Greek | `pl` | Polish | +| `en-GB` | English (United Kingdom) | `pt-BR` | Portuguese (Brazil) | +| `en-US` | English (United States) | `pt-PT` | Portuguese (Portugal) | +| `es-419` | Spanish (Latin America) | `ro` | Romanian | +| `es-ES` | Spanish (Spain) | `ru` | Russian | +| `fa` | Persian | `sv` | Swedish | +| `fi` | Finnish | `th` | Thai | +| `fr` | French | `tr` | Turkish | +| `gd` | Scottish Gaelic | `uk` | Ukrainian | +| `he` | Hebrew | `vi` | Vietnamese | +| `hi` | Hindi | `zh-Hans` | Chinese (Simplified) | +| `hu` | Hungarian | `zh-Hant` | Chinese (Traditional) | +| `id` | Indonesian | | | + +`en-US` is the source locale. Any message a translation has not yet covered +falls back to the English text rather than disappearing. + +A requested tag resolves by these rules, in order: + +1. The exact tag, if a catalogue carries it. +2. A script or region rule for that language. Bare `es` and `es-ES` use + `es-ES`, and every other Spanish region uses `es-419`; bare `pt` and every + Portuguese region except Brazil use `pt-PT`; Chinese resolves by script, with + `zh-CN`, `zh-SG`, and `zh-MY` taking Simplified and `zh-TW`, `zh-HK`, and + `zh-MO` taking Traditional; English outside the United States uses `en-GB`; + and `no` resolves to `nb`. +3. The only catalogue for that language, so `fr-CA` uses `fr` and `de-AT` + uses `de`. +4. `en-US`, for anything still unmatched. + +Regional and script variants that differ in substance are never merged: asking +for `pt-BR` never yields European Portuguese, and asking for `zh-TW` never +yields Simplified Chinese. + +Manual pages and PowerShell help shipped in releases are generated in `en-US` +only. Translated copy reaches users through the running binary, which embeds +every catalogue. + ### Anchor a project with `--directory` `--directory` changes manifest lookup, project configuration discovery and @@ -603,9 +666,14 @@ Common environment equivalents include: - `NETSUKE_EMOJI=never` - `NETSUKE_PROGRESS=never` - `NETSUKE_ACCESSIBILITY=on` +- `NETSUKE_LOCALE=en-US` - `NETSUKE_DEFAULT_TARGETS__0=hello.txt` - `NETSUKE_NINJA=/opt/ninja/bin/ninja` +`NETSUKE_LOCALE` selects the interface language; see +[Choose a language with `--locale`](#choose-a-language-with---locale) for how +it combines with the flag and the system default. + `NETSUKE_NINJA` overrides the Ninja executable used by `build` and `clean`. Leave it unset to use `ninja` from `PATH`, or set another executable name or an absolute path. Empty and non-UTF-8 values fall back to the default. diff --git a/dylint.toml b/dylint.toml index 7d25b347d..ec42ae230 100644 --- a/dylint.toml +++ b/dylint.toml @@ -50,6 +50,14 @@ excluded_paths = [ # each workflow contract crate. The crates themselves stay under policy. "workflow_ci::common", "workflow_release::common", + + # The build script's parsers, included by path so `cargo test` can reach + # them (build scripts are not test targets). Each reads a file Cargo hands + # it through `build_script_build`, which is excluded below for the same + # reason; these entries cover the copies compiled into the test crates. + "build_l10n_keys_tests::keys", + "build_l10n_parser_tests::ftl", + "build_l10n_audit_rules_tests::ftl", ] # Whole crates whose ambient filesystem access lives in the crate root, so a @@ -70,6 +78,11 @@ excluded_paths = [ # `test_support::fs` boundary module rather than exempting the whole crate. excluded_crates = [ "build_script_build", + # Stages the audit's inputs into a TempDir and runs the real audit over + # them and over CARGO_MANIFEST_DIR. Both roots are ambient by + # construction, and the audit modules it includes by path read files the + # build script hands them the same way. + "build_l10n_audit_tests", "advanced_usage_tests", "assert_cmd_tests", "manifest_glob_tests", diff --git a/locales/ar/messages.ftl b/locales/ar/messages.ftl new file mode 100644 index 000000000..ffb4e0fb4 --- /dev/null +++ b/locales/ar/messages.ftl @@ -0,0 +1,405 @@ +# موارد التوطين لواجهة سطر الأوامر في Netsuke. + +cli.about = يصرّف Netsuke بيانات YAML + Jinja إلى خطط بناء بصيغة Ninja. +cli.long_about = يحوّل Netsuke بيانات YAML + Jinja إلى رسوم Ninja قابلة لإعادة الإنتاج، ثم ينفّذ Ninja بإعدادات افتراضية آمنة. +cli.usage = { $usage } + +# نص المساعدة للخيارات العامة. +cli.flag.file.help = مسار ملف بيانات Netsuke المطلوب استخدامه. +cli.flag.directory.help = التنفيذ كما لو كان البدء في هذا الدليل. +cli.flag.config.help = مسار ملف إعدادات، مع تجاوز البحث التلقائي. +cli.flag.jobs.help = تحديد عدد مهام البناء المتوازية. +cli.flag.verbose.help = تفعيل سجلات التشخيص المفصّلة وملخّصات الزمن عند الانتهاء. +cli.flag.locale.help = وسم اللغة لنصوص سطر الأوامر (مثل: en-US أو ar). +cli.flag.fetch_allow_scheme.help = مخطّطات URL إضافية مسموح بها لمساعد fetch. +cli.flag.fetch_allow_host.help = أسماء المضيفين المسموح بها عند تفعيل الرفض الافتراضي. +cli.flag.fetch_block_host.help = أسماء المضيفين المحجوبة دائمًا، حتى إن سُمح بها في موضع آخر. +cli.flag.fetch_default_deny.help = رفض جميع المضيفين افتراضيًا؛ والسماح بالقائمة المعلنة فقط. +cli.flag.json.help = إخراج JSON قابل للقراءة آليًا. +cli.flag.no_input.help = عدم قراءة أي مدخلات تفاعلية أبدًا. +cli.flag.color.help = سياسة الإخراج الملوّن (auto أو always أو never). +cli.flag.emoji.help = سياسة الرموز التعبيرية (auto أو always أو never). +cli.flag.progress.help = سياسة عرض التقدّم (auto أو always أو never). +cli.flag.accessibility.help = سياسة الإخراج الميسّر (auto أو on أو off). +cli.flag.default_targets.help = أهداف البناء الافتراضية عند عدم تحديد أي هدف. + +# أوصاف الأوامر الفرعية. +cli.subcommand.build.about = بناء الأهداف المعرّفة في ملف البيانات (الافتراضي). +cli.subcommand.build.long_about = بناء الأهداف المطلوبة؛ وإن لم يُحدَّد أي هدف تُستخدم أهداف ملف البيانات الافتراضية. +cli.subcommand.clean.about = إزالة مخرجات البناء عبر Ninja. +cli.subcommand.clean.long_about = إنشاء ملف Ninja مؤقت ثم تنفيذ `ninja -t clean`. +cli.subcommand.graph.about = إخراج رسم اعتماديات البناء. الصيغة الافتراضية هي DOT. +cli.subcommand.graph.long_about = إسقاط ملف بيانات Netsuke بعد تحليله إلى رسم بناء قياسي وكتابته بصيغة Graphviz DOT، أو صفحة HTML مكتفية بذاتها عند استخدام `--html`. استخدم `--output <ملف>` للكتابة إلى ملف؛ و`-` يكتب إلى المخرج القياسي. +cli.subcommand.generate.about = توليد ملف بيانات Ninja دون تنفيذ Ninja. +cli.subcommand.generate.long_about = كتابة ملف بيانات Ninja المولَّد إلى المخرج القياسي أو إلى ملف يُختار بـ `--output`. + +# نص المساعدة لخيارات الأمر الفرعي build. +cli.subcommand.build.flag.targets.help = الأهداف المطلوب بناؤها (تُستخدم افتراضيات ملف البيانات عند الإغفال). + +# نص المساعدة لخيارات الأمر الفرعي graph. +cli.subcommand.graph.flag.html.help = عرض الرسم كصفحة HTML مكتفية بذاتها بدلًا من صيغة DOT. +cli.subcommand.graph.flag.output.help = كتابة مخرج الرسم إلى ملف؛ استخدم `-` للمخرج القياسي. + +# نص المساعدة لخيارات الأمر الفرعي generate. +cli.subcommand.generate.flag.output.help = كتابة ملف بيانات Ninja المولَّد إلى ملف بدلًا من المخرج القياسي. + +# أخطاء التحقق في سطر الأوامر. +cli.validation.jobs.invalid_number = ‏{ $value } ليس عددًا صالحًا. +cli.validation.jobs.out_of_range = يجب أن يقع عدد المهام بين { $min } و{ $max }. +cli.validation.scheme.empty = يجب ألّا يكون المخطّط فارغًا. +cli.validation.scheme.invalid_start = يجب أن يبدأ المخطّط «{ $scheme }» بحرف من ASCII. +cli.validation.scheme.invalid = مخطّط غير صالح: «{ $scheme }». +cli.validation.locale.empty = يجب ألّا يكون وسم اللغة فارغًا. +cli.validation.locale.invalid = وسم لغة غير صالح: «{ $locale }». +cli.validation.color.invalid = سياسة ألوان غير صالحة: «{ $value }». القيم الصالحة: auto وalways وnever. +cli.validation.emoji.invalid = سياسة رموز تعبيرية غير صالحة: «{ $value }». القيم الصالحة: auto وalways وnever. +cli.validation.progress.invalid = سياسة تقدّم غير صالحة: «{ $value }». القيم الصالحة: auto وalways وnever. +cli.validation.accessibility.invalid = سياسة تيسير غير صالحة: «{ $value }». القيم الصالحة: auto وon وoff. +cli.validation.config.expected_object = كان يُنتظر أن تُسلسَل قيم سطر الأوامر إلى كائن، لكن ورد { $value }. + +# رسائل الخطأ من Clap. +clap-error-missing-argument = مُعامل مطلوب مفقود: { $argument } +clap-error-missing-subcommand = الأمر الفرعي مفقود. الخيارات المتاحة: { $valid_subcommands } +clap-error-unknown-argument = مُعامل غير معروف: { $argument } +clap-error-invalid-value = قيمة غير صالحة للمُعامل { $argument }: { $value } +clap-error-invalid-subcommand = أمر فرعي غير معروف: { $subcommand } +# ملاحظة: صيغة value-validation تختلف عن invalid-value لتمييز إخفاقات +# المدقّقات المخصّصة (ErrorKind::ValueValidation) عن عدم تطابق الأنواع +# (ErrorKind::InvalidValue). +clap-error-value-validation = فشل التحقق من { $argument }: { $value } + +# أخطاء التنفيذ وسياقه. +runner.manifest.not_found = تعذّر العثور على ملف البيانات «{ $manifest_name }» في { $directory }. +runner.manifest.not_found.help = تأكّد من وجود ملف البيانات أو مرّر `--file` مع المسار الصحيح. +runner.manifest.path_missing_name = مسار ملف البيانات «{ $path }» لا يتضمّن اسم ملف. +runner.manifest.path_utf8 = مسار ملف البيانات «{ $path }» ليس UTF-8 صالحًا. +runner.manifest.directory_utf8 = مسار دليل ملف البيانات «{ $path }» ليس UTF-8 صالحًا. +runner.manifest.directory_label = الدليل `{ $directory }` +runner.manifest.current_directory_label = الدليل الحالي +runner.context.network_policy = تعذّر بناء سياسة الشبكة. +runner.context.load_manifest = تعذّر تحميل ملف البيانات من { $path }. +runner.context.serialise_manifest = تعذّرت سَلسَلة ملف البيانات. +runner.context.build_graph = تعذّر بناء الرسم من ملف البيانات. +runner.context.generate_ninja = تعذّر توليد ملف بيانات Ninja. +runner.context.render_graph = تعذّر عرض مخرج الرسم. + +runner.io.create_temp_file = تعذّر إنشاء ملف Ninja المؤقت. +runner.io.write_temp_ninja = تعذّرت الكتابة إلى ملف Ninja المؤقت. +runner.io.flush_temp_ninja = تعذّر إفراغ ذاكرة ملف Ninja المؤقت. +runner.io.sync_temp_ninja = تعذّرت مزامنة ملف Ninja المؤقت. +runner.io.create_parent_dir = تعذّر إنشاء الدليل الأصل { $path }. +runner.io.create_ninja_file = تعذّر إنشاء ملف Ninja في { $path }. +runner.io.write_ninja_file = تعذّرت الكتابة إلى ملف Ninja في { $path }. +runner.io.flush_ninja_file = تعذّر إفراغ ذاكرة ملف Ninja في { $path }. +runner.io.sync_ninja_file = تعذّرت مزامنة ملف Ninja في { $path }. +runner.io.open_ambient_dir = تعذّر فتح الدليل المحيط. +runner.io.no_existing_ancestor = لا يوجد دليل أعلى قائم للمسار { $path }. +runner.io.derive_relative_path = تعذّر اشتقاق مسار Ninja النسبي. +runner.io.non_utf8_path = المسارات غير المرمّزة بـ UTF-8 غير مدعومة (المسار: { $path }). +runner.io.write_stdout = تعذّرت كتابة ملف بيانات Ninja إلى المخرج القياسي. +runner.io.flush_stdout = تعذّر إفراغ ذاكرة المخرج القياسي. + +# تشخيصات ملف البيانات. +manifest.parse = فشل تحليل ملف البيانات. +manifest.structure_error = خطأ في بنية ملف البيانات عند { $name }: { $details } +manifest.yaml.parse = خطأ في تحليل YAML في السطر { $line } والعمود { $column }: { $details } +manifest.yaml.label = ‏YAML غير صالح +manifest.yaml.hint.tabs = لا يسمح YAML بمحارف الجدولة؛ استخدم المسافات في الإزاحة. +manifest.yaml.hint.list_item = يجب أن تبدأ عناصر قوائم YAML بـ «-» وأن تكون مُزاحة بشكل صحيح. +manifest.yaml.hint.expected_colon = يبدو هذا مدخلًا في تخطيط؛ ينقص «:» بعد المفتاح. +manifest.yaml.hint.mapping_values = تتطلّب تخطيطات YAML قيمة بعد «:» (أو كتلة متداخلة). +manifest.yaml.hint.invalid_token = رمز YAML غير صالح أو غير متوقّع. +manifest.yaml.hint.escape = هرّب الشرطات المائلة العكسية أو احذف تسلسلات التهريب غير الصالحة. +manifest.env.missing = متغيّر البيئة المطلوب «{ $name }» غير مضبوط. +manifest.env.invalid_utf8 = يتضمّن متغيّر البيئة «{ $name }» ترميز UTF-8 غير صالح. +manifest.vars.not_object = يجب أن يكون `vars` في ملف البيانات تخطيطًا أو كائنًا. +manifest.read_failed = تعذّرت قراءة ملف البيانات من { $path }. +manifest.resolve_workspace_root = تعذّر تحديد جذر مساحة العمل. +manifest.workspace_non_utf8 = مسار جذر مساحة العمل «{ $path }» ليس UTF-8 صالحًا. +manifest.path_non_utf8 = مسار ملف البيانات «{ $manifest }» ليس UTF-8 صالحًا: { $path }. +manifest.path_missing_name = مسار ملف البيانات «{ $path }» لا يتضمّن اسم ملف. +manifest.open_workspace_failed = تعذّر فتح مساحة العمل { $workspace } لأجل ملف البيانات { $manifest }. +manifest.foreach.not_iterable = تعبير `foreach` غير قابل للتكرار. +manifest.foreach.serialise_item = تعذّرت سَلسَلة عنصر `foreach`. +manifest.when.empty = يجب ألّا يكون تعبير `when` فارغًا. +manifest.when.eval_error = تعذّر تقييم تعبير `when` «{ $expr }». +manifest.when.template_error = تعذّر عرض قالب `when` «{ $expr }». +manifest.target.vars_not_object = يجب أن يكون `vars` الخاص بالهدف كائنًا، لكن ورد { $value }. +manifest.vars.entry_not_object = يجب أن يكون مدخل `vars` في ملف البيانات كائنًا. +manifest.field_not_string = يجب أن يكون الحقل «{ $field }» سلسلة نصية. +manifest.expression.parse_error = تعذّر تحليل تعبير { $name }. +manifest.expression.eval_error = تعذّر تقييم تعبير { $name }. + +# تشخيصات ماكروهات ملف البيانات. +manifest.macro.signature_missing_identifier = ينقص توقيع الماكرو مُعرّفًا. +manifest.macro.signature_missing_params = تنقص توقيع الماكرو مُعاملات. +manifest.macro.compile_failed = تعذّر تصريف الماكرو { $name }. +manifest.macro.sequence_invalid = يجب تعريف الماكروهات كتخطيط من الأسماء إلى القوالب. +manifest.macro.register_failed = تعذّر تسجيل ماكروهات ملف البيانات. +manifest.macro.not_initialised = بيئة الماكروهات غير مهيّأة. +manifest.macro.caller_invalid = يجب أن يكون مُستدعي الماكرو سلسلة نصية. +manifest.macro.template_load_failed = تعذّر تحميل قالب الماكرو. +manifest.macro.init_failed = تعذّرت تهيئة بيئة الماكروهات. +manifest.macro.missing = الماكرو { $name } مفقود. + +# أخطاء أنماط glob في ملف البيانات. +manifest.glob.unmatched_brace = نمط glob غير صالح «{ $pattern }»: المحرف «{ $character }» بلا مقابل في الموضع { $position }. +manifest.glob.invalid_pattern = نمط glob غير صالح «{ $pattern }»: { $detail }. +manifest.glob.unknown_pattern_error = خطأ نمط غير معروف. +manifest.glob.io_failed = فشل glob للنمط «{ $pattern }»: { $detail }. +manifest.glob.unknown_io_error = خطأ إدخال/إخراج غير معروف. + +# أخطاء التمثيل الوسيط. +ir.rule_not_found = تعذّر العثور على القاعدة «{ $rule }» التي يشير إليها الهدف «{ $target }». +ir.multiple_rules = يجب أن يشير الهدف «{ $target }» إلى قاعدة واحدة فقط، لكن ورد { $rules }. +ir.empty_rule = يجب أن يشير الهدف «{ $target }» إلى قاعدة. +ir.duplicate_outputs = رُصدت مخرجات مكرّرة: { $outputs }. +ir.circular_dependency = رُصد اعتماد دائري: { $cycle }. +ir.action_serialisation = تعذّرت سَلسَلة الإجراء: { $details }. +ir.invalid_command = إقحام غير صالح داخل الأمر: { $snippet }. + +# أخطاء توليد ملفات Ninja. +ninja_gen.missing_action = الإجراء «{ $id }» الذي تشير إليه حافة بناء مفقود. +ninja_gen.format = تعذّر تنسيق مخرجات ملف بيانات Ninja. + +# التحقق من أنماط المضيفين. +host_pattern.empty = يجب ألّا يكون نمط المضيف فارغًا. +host_pattern.contains_scheme = يجب ألّا يتضمّن نمط المضيف «{ $pattern }» مخطّط URL. +host_pattern.contains_slash = يجب ألّا يتضمّن نمط المضيف «{ $pattern }» المحرف «/». +host_pattern.missing_suffix = يجب أن يتضمّن نمط المضيف «{ $pattern }» لاحقة بعد «*.». +host_pattern.empty_label = يتضمّن نمط المضيف «{ $pattern }» تسمية فارغة. +host_pattern.invalid_chars = يتضمّن نمط المضيف «{ $pattern }» محارف غير صالحة. +host_pattern.invalid_label_edge = يجب ألّا تبدأ تسميات نمط المضيف «{ $pattern }» بـ «-» أو تنتهي به. +host_pattern.label_too_long = يتضمّن نمط المضيف «{ $pattern }» تسمية تتجاوز 63 محرفًا. +host_pattern.too_long = يتجاوز نمط المضيف «{ $pattern }» حدّ 255 محرفًا. + +# سياسة الشبكة. +network_policy.scheme.empty = يجب ألّا يكون المخطّط فارغًا. +network_policy.scheme.invalid = يتضمّن المخطّط «{ $scheme }» محارف غير صالحة. +network_policy.allowlist.empty = يجب ألّا تكون قائمة المضيفين المسموح بهم فارغة. +network_policy.scheme.not_allowed = المخطّط «{ $scheme }» غير مسموح به. +network_policy.missing_host = لا يتضمّن العنوان URL مضيفًا. +network_policy.host.blocked = المضيف «{ $host }» محجوب بموجب السياسة. +network_policy.host.not_allowlisted = المضيف «{ $host }» ليس ضمن قائمة المسموح بهم. + +# إعدادات المكتبة القياسية. +stdlib.config.default_fetch_cache_invalid = يجب أن يكون المسار الافتراضي لذاكرة fetch المخبّأة نسبيًا. +stdlib.config.default_which_cache_invalid = يجب أن تكون السعة الافتراضية لذاكرة which المخبّأة موجبة. +stdlib.config.workspace_root_absolute = يجب أن يكون مسار جذر مساحة العمل مطلقًا. +stdlib.config.fetch_response_limit_positive = يجب أن يكون حدّ استجابة fetch موجبًا. +stdlib.config.command_output_limit_positive = يجب أن يكون حدّ التقاط مخرجات الأوامر موجبًا. +stdlib.config.command_stream_limit_positive = يجب أن يكون حدّ تدفّق الأوامر موجبًا. +stdlib.config.which_cache_capacity_positive = يجب أن تكون سعة ذاكرة which المخبّأة موجبة. +stdlib.config.skip_dir_empty = يجب ألّا تكون مداخل الأدلة المتجاوَزة فارغة. +stdlib.config.skip_dir_navigation = يجب ألّا تتضمّن مداخل الأدلة المتجاوَزة «..». +stdlib.config.skip_dir_separator = يجب ألّا تتضمّن مداخل الأدلة المتجاوَزة فواصل مسار. +stdlib.config.fetch_cache_empty = يجب ألّا يكون مسار ذاكرة fetch المخبّأة فارغًا. +stdlib.config.fetch_cache_not_relative = يجب أن يكون مسار ذاكرة fetch المخبّأة نسبيًا، لكن ورد { $path }. +stdlib.config.fetch_cache_escapes = يجب ألّا يخرج مسار ذاكرة fetch المخبّأة عن مساحة العمل: { $path }. +stdlib.config.open_workspace_root = تعذّر فتح الدليل الحالي بوصفه جذر مساحة عمل stdlib. +stdlib.config.resolve_cwd = تعذّر تحديد الدليل الحالي بوصفه جذر مساحة عمل stdlib. +stdlib.config.cwd_non_utf8 = يتضمّن الدليل الحالي أجزاءً ليست UTF-8: { $path }. + +# تشخيصات مساعد fetch. +stdlib.fetch.url_invalid = عنوان URL غير صالح «{ $url }»: { $details }. +stdlib.fetch.disallowed = العنوان URL «{ $url }» غير مسموح به: { $details }. +stdlib.fetch.failed = تعذّر جلب «{ $url }»: { $details }. +stdlib.fetch.cache_read_failed = تعذّرت قراءة مدخل الذاكرة المخبّأة «{ $name }»: { $details }. +stdlib.fetch.cache_open_failed = تعذّر فتح مدخل الذاكرة المخبّأة «{ $name }»: { $details }. +stdlib.fetch.response_read_failed = تعذّرت قراءة الاستجابة من «{ $url }»: { $details }. +stdlib.fetch.response_buffer_overflow = فاض المخزن المؤقت أثناء قراءة «{ $url }». +stdlib.fetch.cache_write_failed = تعذّرت كتابة الذاكرة المخبّأة لـ «{ $url }»: { $details }. +stdlib.fetch.response_limit_exceeded = تجاوزت الاستجابة من «{ $url }» حدّ { $limit } بايت. +stdlib.fetch.cache_limit_exceeded = تجاوزت الاستجابة المخبّأة «{ $name }» حدّ { $limit } بايت. +stdlib.fetch.io_failed = فشل الإجراء «{ $action }» على { $path }: { $details }. +stdlib.fetch.action.sync_cache = مزامنة ذاكرة fetch المخبّأة +stdlib.fetch.action.create_cache_dir = إنشاء دليل ذاكرة fetch المخبّأة +stdlib.fetch.action.open_cache_dir = فتح دليل ذاكرة fetch المخبّأة +stdlib.fetch.action.stat_cache = قراءة بيانات مدخل ذاكرة fetch المخبّأة +stdlib.fetch.action.open_cache_entry = فتح مدخل ذاكرة fetch المخبّأة + +# تشخيصات مساعد الأوامر. +stdlib.command.location = الأمر «{ $command }» في القالب «{ $template }» +stdlib.command.spawn_failed = تعذّر تشغيل { $location }: { $details }. +stdlib.command.io_failed = فشل { $location }: { $details }. +stdlib.command.closed_input_early = أُغلق المدخل قبل اكتمال الكتابة إلى الأمر. +stdlib.command.broken_pipe = انقطعت الأنبوبة أثناء تنفيذ { $location }: { $details }. +stdlib.command.terminated_by_signal = أُنهي { $location } بإشارة. +stdlib.command.exited_with_status = انتهى { $location } بالحالة { $status }. +stdlib.command.output_limit_exceeded = تجاوز { $location } حدّ { $mode } البالغ { $limit } بايت للتدفّق { $stream }. +stdlib.command.timeout = تجاوز { $location } المهلة البالغة { $seconds } ثانية. +stdlib.command.exit_status_suffix = ‏(حالة الخروج { $status }) +stdlib.command.signal_suffix = ‏(أُنهي بإشارة) +stdlib.command.shell.empty = يجب ألّا يكون أمر الصدفة فارغًا. +stdlib.command.grep.empty_pattern = يجب ألّا يكون نمط grep فارغًا. +stdlib.command.grep.flags_not_string = يجب أن تكون رايات grep سلاسل نصية. +stdlib.command.quote.invalid = تعذّر وضع { $arg } بين علامتي اقتباس: { $details }. +stdlib.command.quote.line_break = لا يمكن وضع المعاملات التي تتضمّن إرجاع أوّل السطر أو تغذية السطر بين علامتي اقتباس بأمان. +stdlib.command.input_undefined = قيمة المدخل غير معرّفة. +stdlib.command.tempfile.root_required = يلزم جذر مساحة العمل لإنشاء ملفات الأوامر المؤقتة. +stdlib.command.tempfile.create_failed = تعذّر إنشاء الملف المؤقت للأمر: { $details }. +stdlib.command.options.invalid_utf8 = يجب أن يكون مفتاح خيار الأمر بترميز UTF-8 صالح. +stdlib.command.option.mode_not_string = يجب أن يكون وضع الإخراج سلسلة نصية. +stdlib.command.options.invalid_type = يجب أن تكون خيارات الأمر كائنًا. +stdlib.command.output.mode_unsupported = وضع إخراج غير مدعوم: «{ $mode }». +stdlib.command.output.mode.capture = الالتقاط +stdlib.command.output.mode.streaming = التدفّق +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# تشخيصات مساعد المسارات. +stdlib.path.io.failed = فشل الإجراء «{ $action }» على { $path } ({ $label }). +stdlib.path.io.failed_with_detail = فشل الإجراء «{ $action }» على { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = فشل الإجراء «{ $action }» على { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = غير موجود +stdlib.path.io.permission_denied = رُفض الإذن +stdlib.path.io.already_exists = موجود سلفًا +stdlib.path.io.invalid_input = مدخل غير صالح +stdlib.path.io.invalid_data = بيانات غير صالحة +stdlib.path.io.timed_out = انتهت المهلة +stdlib.path.io.interrupted = قوطع +stdlib.path.io.would_block = سيؤدي إلى التعليق +stdlib.path.io.write_zero = كُتبت صفر بايت +stdlib.path.io.unexpected_eof = نهاية ملف غير متوقّعة +stdlib.path.io.broken_pipe = انقطاع الأنبوبة +stdlib.path.io.connection_refused = رُفض الاتصال +stdlib.path.io.connection_reset = أُعيد ضبط الاتصال +stdlib.path.io.connection_aborted = أُجهض الاتصال +stdlib.path.io.not_connected = غير متّصل +stdlib.path.io.addr_in_use = العنوان قيد الاستخدام +stdlib.path.io.addr_not_available = العنوان غير متاح +stdlib.path.io.out_of_memory = نفدت الذاكرة +stdlib.path.io.unsupported = غير مدعوم +stdlib.path.io.file_too_large = الملف أكبر من اللازم +stdlib.path.io.resource_busy = المورد مشغول +stdlib.path.io.executable_busy = الملف التنفيذي مشغول +stdlib.path.io.deadlock = تعطّل متبادل +stdlib.path.io.crosses_devices = يعبر حدود الأجهزة +stdlib.path.io.too_many_links = روابط أكثر من اللازم +stdlib.path.io.invalid_filename = اسم ملف غير صالح +stdlib.path.io.arg_list_too_long = قائمة المعاملات أطول من اللازم +stdlib.path.io.stale_handle = مقبض ملف شبكي قديم +stdlib.path.io.storage_full = مساحة التخزين ممتلئة +stdlib.path.io.not_seekable = لا يقبل تحديد الموضع +stdlib.path.io.network_down = الشبكة متوقّفة +stdlib.path.io.network_unreachable = تعذّر الوصول إلى الشبكة +stdlib.path.io.host_unreachable = تعذّر الوصول إلى المضيف +stdlib.path.io.other = خطأ إدخال/إخراج +stdlib.path.action.canonicalize = التقييس +stdlib.path.action.open_directory = فتح الدليل +stdlib.path.action.stat = قراءة البيانات +stdlib.path.action.read = القراءة +stdlib.path.action.open_file = فتح الملف +stdlib.path.with_suffix.empty_separator = يتطلّب with_suffix فاصلًا غير فارغ. +stdlib.path.relative_to.mismatch = المسار { $path } ليس نسبيًا إلى { $root }. +stdlib.path.expanduser.unsupported = توسيع ~ لمستخدم بعينه غير مدعوم. +stdlib.path.expanduser.no_home = تعذّر توسيع ~: لم يُضبط أي متغيّر بيئة لدليل المنزل. +stdlib.path.contents.unsupported_encoding = ترميز غير مدعوم: «{ $encoding }». +stdlib.path.hash.unsupported_algorithm = خوارزمية تلبيد غير مدعومة: «{ $algorithm }». +stdlib.path.hash.unsupported_algorithm_legacy = خوارزمية تلبيد غير مدعومة: «{ $algorithm }» (فعّل الميزة «{ $feature }»). + +# تشخيصات مساعدات المجموعات. +stdlib.collections.flatten.expected_sequence = توقّع flatten عناصر متتالية لكنه وجد { $kind }. +stdlib.collections.group_by.empty_attribute = يتطلّب group_by سمة غير فارغة. +stdlib.collections.group_by.unresolved = تعذّر على group_by إيجاد «{ $attr }» في عنصر من النوع { $kind }. + +# تشخيصات مساعدات الزمن. +stdlib.time.offset.invalid = إزاحة now «{ $offset }» غير صالحة: المتوقّع «+HH:MM[:SS]» أو «Z». +stdlib.time.timedelta.overflow = فاض timedelta عند إضافة { $component }. +stdlib.time.label.weeks = أسابيع +stdlib.time.label.days = أيام +stdlib.time.label.hours = ساعات +stdlib.time.label.minutes = دقائق +stdlib.time.label.seconds = ثوانٍ +stdlib.time.label.milliseconds = أجزاء من الألف من الثانية +stdlib.time.label.microseconds = أجزاء من المليون من الثانية +stdlib.time.label.nanoseconds = أجزاء من المليار من الثانية + +# تشخيصات مساعد which. +stdlib.which.not_found = ‏[netsuke::jinja::which::not_found] تعذّر العثور على الأمر «{ $command }» بعد فحص { $count } من مداخل PATH. معاينة: { $preview } +stdlib.which.not_found.hint.cwd_auto = تُتجاهل الأجزاء الفارغة من PATH؛ استخدم cwd_mode="auto" لتضمين دليل العمل. +stdlib.which.not_found.hint.cwd_always = اضبط cwd_mode="always" لتضمين الدليل الحالي. +stdlib.which.direct_not_found = ‏[netsuke::jinja::which::not_found] الأمر «{ $command }» في «{ $path }» غير موجود أو غير قابل للتنفيذ. +stdlib.which.args_error = ‏[netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = ‏<فارغ> +stdlib.which.path_entry.non_utf8 = يتضمّن المدخل رقم { $index } في PATH محارف ليست UTF-8؛ ويتطلّب Netsuke مسارات بترميز UTF-8. +stdlib.which.command.empty = يتطلّب which سلسلة نصية غير فارغة. +stdlib.which.cwd_mode.invalid = يجب أن تكون قيمة cwd_mode إحدى «auto» أو «always» أو «never»، لكن ورد «{ $mode }». +stdlib.which.cwd.resolve_failed = تعذّر تحديد الدليل الحالي: { $details }. +stdlib.which.cwd.non_utf8 = يتضمّن الدليل الحالي أجزاءً ليست UTF-8. +stdlib.which.canonicalize_failed = تعذّر تقييس «{ $path }»: { $details }. +stdlib.which.is_executable = تعذّر التحقق ممّا إذا كان «{ $path }» قابلًا للتنفيذ: { $details }. +stdlib.which.canonicalize_non_utf8 = يتضمّن المسار المقيَّس أجزاءً ليست UTF-8. +stdlib.which.workspace_non_utf8 = يتضمّن مسار مساحة العمل أجزاءً ليست UTF-8 أثناء تحديد الأمر «{ $command }»: { $path }. +stdlib.which.walkdir_error = خطأ أثناء اجتياز مساحة العمل بحثًا عن الأمر: { $details }. + +# تسجيل المكتبة القياسية. +stdlib.register.open_dir = تعذّر فتح الدليل الحالي لتسجيل stdlib. +stdlib.register.resolve_dir = تعذّر تحديد الدليل الحالي لتسجيل stdlib. +stdlib.register.dir_non_utf8 = يتضمّن الدليل الحالي أجزاءً ليست UTF-8: { $path }. + +# تقارير الحالة لوضع الإخراج الميسّر. +status.state.pending = في الانتظار +status.state.running = قيد التنفيذ +status.state.done = مكتملة +status.state.failed = فاشلة +status.stage.label = المرحلة { $current }/{ $total }: { $description } +status.stage.summary = ‏[{ $state }] { $label } +status.stage.summary_with_task = ‏[{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = المهمة { $current }/{ $total } +status.task.progress_update = ‏{ $task }: { $description } +status.stage.manifest_ingestion = قراءة ملف البيانات +status.stage.initial_yaml_parsing = تحليل مستند YAML +status.stage.template_expansion = توسيع توجيهات القوالب +status.stage.final_rendering = فكّ سَلسَلة قيم ملف البيانات وعرضها +status.stage.ir_generation_validation = بناء رسم الاعتماديات والتحقق منه +status.stage.ninja_synthesis = تركيب خطة بناء Ninja +status.stage.ninja_synthesis_execute = تركيب خطة Ninja وتنفيذ { $tool } +status.stage.graph_rendering = عرض مخرج الرسم +status.stage.graph_rendering_with_tool = عرض { $tool } +status.complete = اكتمل { $tool }. +status.timing.summary_header = ملخّص الزمن حسب المرحلة: +status.timing.stage_line = ‏- { $label }: { $duration } +status.timing.total_line = الزمن الكلي لسلسلة المعالجة: { $duration } +status.tool.build = البناء +status.tool.clean = التنظيف +status.tool.graph = الرسم +status.tool.graph_html = الرسم (HTML) +status.tool.generate = التوليد + +# نصوص عرض الرسم بصيغة HTML. +graph.html.title = رسم بناء Netsuke +graph.html.heading = رسم بناء Netsuke +graph.html.description = رسم بناء عرضه Netsuke +graph.html.outline.summary = الأهداف والاعتماديات (مخطّط نصي) +graph.html.outline.no_inputs = لا توجد مدخلات +graph.html.noscript.notice = ‏JavaScript معطّلة. المخطّط النصي أعلاه هو الرسم كاملًا، ويليه مصدر DOT. + +# البادئات الدلالية للإخراج الميسّر. +semantic.prefix.error = خطأ: +semantic.prefix.warning = تحذير: +semantic.prefix.success = نجاح: +semantic.prefix.info = معلومة: +semantic.prefix.timing = الزمن: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# أمثلة على صيغ الجمع للمترجمين. +# تستخدم العربية فئات CLDR الست: `zero` و`one` و`two` و`few` (3–10) +# و`many` (11–99) و`other`، ويتغيّر تمييز العدد بينها. +example.files_processed = { $count -> + [zero] لم تُعالَج أي ملفات. + [one] عولج ملف واحد. + [two] عولج ملفان. + [few] عولجت { $count } ملفات. + [many] عولج { $count } ملفًا. + *[other] عولج { $count } ملف. +} + +example.errors_found = { $count -> + [0] لم يُعثر على أي أخطاء. + [one] عُثر على خطأ واحد. + [two] عُثر على خطأين. + [few] عُثر على { $count } أخطاء. + [many] عُثر على { $count } خطأً. + *[other] عُثر على { $count } خطأ. +} diff --git a/locales/cs/messages.ftl b/locales/cs/messages.ftl new file mode 100644 index 000000000..ff4a947e4 --- /dev/null +++ b/locales/cs/messages.ftl @@ -0,0 +1,402 @@ +# Lokalizační zdroje příkazové řádky Netsuke. + +cli.about = Netsuke překládá manifesty YAML + Jinja na plány sestavení pro Ninju. +cli.long_about = Netsuke převádí manifesty YAML + Jinja na reprodukovatelné grafy Ninja a spouští Ninju s bezpečným výchozím nastavením. +cli.usage = { $usage } + +# Text nápovědy globálních přepínačů. +cli.flag.file.help = Cesta k souboru manifestu Netsuke, který se má použít. +cli.flag.directory.help = Spustit, jako by byl program spuštěn v tomto adresáři. +cli.flag.config.help = Cesta ke konfiguračnímu souboru; obchází automatické hledání. +cli.flag.jobs.help = Nastavit počet souběžných úloh sestavení. +cli.flag.verbose.help = Zapnout podrobné diagnostické protokolování a souhrny časů po dokončení. +cli.flag.locale.help = Jazyková značka textů příkazové řádky (například: en-US, cs). +cli.flag.fetch_allow_scheme.help = Další schémata URL povolená pro pomocníka fetch. +cli.flag.fetch_allow_host.help = Názvy hostitelů povolené, když je zapnuto výchozí odmítání. +cli.flag.fetch_block_host.help = Názvy hostitelů, které se vždy blokují, i když jsou povoleny jinde. +cli.flag.fetch_default_deny.help = Ve výchozím stavu odmítat všechny hostitele; povolit jen uvedený seznam. +cli.flag.json.help = Vypisovat strojově čitelný výstup JSON. +cli.flag.no_input.help = Nikdy nečíst interaktivní vstup. +cli.flag.color.help = Zásada barevného výstupu (auto, always, never). +cli.flag.emoji.help = Zásada používání emodži (auto, always, never). +cli.flag.progress.help = Zásada zobrazování průběhu (auto, always, never). +cli.flag.accessibility.help = Zásada přístupného výstupu (auto, on, off). +cli.flag.default_targets.help = Výchozí cíle sestavení, pokud není žádný uveden. + +# Popisy podpříkazů. +cli.subcommand.build.about = Sestavit cíle definované v manifestu (výchozí). +cli.subcommand.build.long_about = Sestavit požadované cíle; není-li žádný uveden, použít výchozí cíle z manifestu. +cli.subcommand.clean.about = Odstranit artefakty sestavení prostřednictvím Ninji. +cli.subcommand.clean.long_about = Vytvořit dočasný soubor Ninja a poté spustit `ninja -t clean`. +cli.subcommand.graph.about = Vypsat graf závislostí sestavení. Výchozí formát je DOT. +cli.subcommand.graph.long_about = Převést načtený manifest Netsuke na kanonický graf sestavení a zapsat jej jako Graphviz DOT, případně s přepínačem `--html` jako samostatnou stránku HTML. Zápis do souboru zajistí `--output `; `-` zapisuje na standardní výstup. +cli.subcommand.generate.about = Vytvořit manifest Ninja bez spuštění Ninji. +cli.subcommand.generate.long_about = Zapsat vytvořený manifest Ninja na standardní výstup nebo do souboru zvoleného přepínačem `--output`. + +# Text nápovědy přepínačů podpříkazu build. +cli.subcommand.build.flag.targets.help = Cíle k sestavení (při vynechání se použijí výchozí cíle z manifestu). + +# Text nápovědy přepínačů podpříkazu graph. +cli.subcommand.graph.flag.html.help = Vykreslit graf jako samostatnou stránku HTML místo formátu DOT. +cli.subcommand.graph.flag.output.help = Zapsat artefakt grafu do SOUBORU; pro standardní výstup použijte `-`. + +# Text nápovědy přepínačů podpříkazu generate. +cli.subcommand.generate.flag.output.help = Zapsat vytvořený manifest Ninja do SOUBORU místo na standardní výstup. + +# Chyby ověření na příkazové řádce. +cli.validation.jobs.invalid_number = { $value } není platné číslo. +cli.validation.jobs.out_of_range = Počet úloh musí být mezi { $min } a { $max }. +cli.validation.scheme.empty = Schéma nesmí být prázdné. +cli.validation.scheme.invalid_start = Schéma „{ $scheme }“ musí začínat písmenem ASCII. +cli.validation.scheme.invalid = Neplatné schéma „{ $scheme }“. +cli.validation.locale.empty = Jazyková značka nesmí být prázdná. +cli.validation.locale.invalid = Neplatná jazyková značka „{ $locale }“. +cli.validation.color.invalid = Neplatná zásada barev „{ $value }“. Platné možnosti: auto, always, never. +cli.validation.emoji.invalid = Neplatná zásada emodži „{ $value }“. Platné možnosti: auto, always, never. +cli.validation.progress.invalid = Neplatná zásada průběhu „{ $value }“. Platné možnosti: auto, always, never. +cli.validation.accessibility.invalid = Neplatná zásada přístupnosti „{ $value }“. Platné možnosti: auto, on, off. +cli.validation.config.expected_object = Hodnoty z příkazové řádky se měly serializovat do objektu, obdrženo { $value }. + +# Chybové zprávy z Clapu. +clap-error-missing-argument = Chybí povinný argument: { $argument } +clap-error-missing-subcommand = Chybí podpříkaz. Dostupné možnosti: { $valid_subcommands } +clap-error-unknown-argument = Neznámý argument: { $argument } +clap-error-invalid-value = Neplatná hodnota argumentu { $argument }: { $value } +clap-error-invalid-subcommand = Neznámý podpříkaz: { $subcommand } +# Poznámka: value-validation je formulováno jinak než invalid-value, aby se +# odlišily chyby vlastních ověřovačů (ErrorKind::ValueValidation) od neshody +# typů (ErrorKind::InvalidValue). +clap-error-value-validation = Ověření selhalo pro { $argument }: { $value } + +# Chyby a kontext běhu. +runner.manifest.not_found = Manifest „{ $manifest_name }“ nebyl v adresáři { $directory } nalezen. +runner.manifest.not_found.help = Ověřte, že manifest existuje, nebo zadejte `--file` se správnou cestou. +runner.manifest.path_missing_name = Cesta k manifestu „{ $path }“ neobsahuje název souboru. +runner.manifest.path_utf8 = Cesta k manifestu „{ $path }“ není platné UTF-8. +runner.manifest.directory_utf8 = Cesta k adresáři manifestu „{ $path }“ není platné UTF-8. +runner.manifest.directory_label = adresář `{ $directory }` +runner.manifest.current_directory_label = aktuální adresář +runner.context.network_policy = Síťovou zásadu se nepodařilo sestavit. +runner.context.load_manifest = Manifest v { $path } se nepodařilo načíst. +runner.context.serialise_manifest = Manifest se nepodařilo serializovat. +runner.context.build_graph = Z manifestu se nepodařilo sestavit graf. +runner.context.generate_ninja = Manifest Ninja se nepodařilo vytvořit. +runner.context.render_graph = Artefakt grafu se nepodařilo vykreslit. + +runner.io.create_temp_file = Dočasný soubor Ninja se nepodařilo vytvořit. +runner.io.write_temp_ninja = Dočasný soubor Ninja se nepodařilo zapsat. +runner.io.flush_temp_ninja = Vyrovnávací paměť dočasného souboru Ninja se nepodařilo vyprázdnit. +runner.io.sync_temp_ninja = Dočasný soubor Ninja se nepodařilo synchronizovat. +runner.io.create_parent_dir = Nadřazený adresář { $path } se nepodařilo vytvořit. +runner.io.create_ninja_file = Soubor Ninja v { $path } se nepodařilo vytvořit. +runner.io.write_ninja_file = Soubor Ninja v { $path } se nepodařilo zapsat. +runner.io.flush_ninja_file = Vyrovnávací paměť souboru Ninja v { $path } se nepodařilo vyprázdnit. +runner.io.sync_ninja_file = Soubor Ninja v { $path } se nepodařilo synchronizovat. +runner.io.open_ambient_dir = Okolní adresář se nepodařilo otevřít. +runner.io.no_existing_ancestor = Pro { $path } neexistuje žádný nadřazený adresář. +runner.io.derive_relative_path = Relativní cestu pro Ninju se nepodařilo odvodit. +runner.io.non_utf8_path = Cesty, které nejsou v UTF-8, nejsou podporovány (cesta: { $path }). +runner.io.write_stdout = Manifest Ninja se nepodařilo zapsat na standardní výstup. +runner.io.flush_stdout = Vyrovnávací paměť standardního výstupu se nepodařilo vyprázdnit. + +# Diagnostika manifestu. +manifest.parse = Zpracování manifestu selhalo. +manifest.structure_error = Chyba struktury manifestu u { $name }: { $details } +manifest.yaml.parse = Chyba zpracování YAML na řádku { $line }, sloupci { $column }: { $details } +manifest.yaml.label = neplatný YAML +manifest.yaml.hint.tabs = YAML nepovoluje tabulátory; k odsazení používejte mezery. +manifest.yaml.hint.list_item = Položky seznamu YAML musí začínat znakem „-“ a být správně odsazené. +manifest.yaml.hint.expected_colon = Vypadá to na položku mapování; za klíčem chybí „:“. +manifest.yaml.hint.mapping_values = Mapování YAML vyžadují za „:“ hodnotu (nebo vnořený blok). +manifest.yaml.hint.invalid_token = Token YAML je neplatný nebo neočekávaný. +manifest.yaml.hint.escape = Escapujte zpětná lomítka nebo odstraňte neplatné únikové sekvence. +manifest.env.missing = Povinná proměnná prostředí „{ $name }“ není nastavena. +manifest.env.invalid_utf8 = Proměnná prostředí „{ $name }“ obsahuje neplatné UTF-8. +manifest.vars.not_object = Položka `vars` manifestu musí být mapování nebo objekt. +manifest.read_failed = Manifest v { $path } se nepodařilo přečíst. +manifest.resolve_workspace_root = Kořen pracovního prostoru se nepodařilo určit. +manifest.workspace_non_utf8 = Kořenová cesta pracovního prostoru „{ $path }“ není platné UTF-8. +manifest.path_non_utf8 = Cesta manifestu „{ $manifest }“ není platné UTF-8: { $path }. +manifest.path_missing_name = Cesta k manifestu „{ $path }“ neobsahuje název souboru. +manifest.open_workspace_failed = Pracovní prostor { $workspace } se nepodařilo otevřít pro manifest { $manifest }. +manifest.foreach.not_iterable = Výraz `foreach` nelze procházet. +manifest.foreach.serialise_item = Položku výrazu `foreach` se nepodařilo serializovat. +manifest.when.empty = Výraz `when` nesmí být prázdný. +manifest.when.eval_error = Výraz `when` „{ $expr }“ se nepodařilo vyhodnotit. +manifest.when.template_error = Šablonu `when` „{ $expr }“ se nepodařilo vykreslit. +manifest.target.vars_not_object = Položka `vars` cíle musí být objekt, obdrženo { $value }. +manifest.vars.entry_not_object = Položka `vars` manifestu musí být objekt. +manifest.field_not_string = Pole „{ $field }“ musí být řetězec. +manifest.expression.parse_error = Výraz { $name } se nepodařilo zpracovat. +manifest.expression.eval_error = Výraz { $name } se nepodařilo vyhodnotit. + +# Diagnostika maker manifestu. +manifest.macro.signature_missing_identifier = V hlavičce makra chybí identifikátor. +manifest.macro.signature_missing_params = V hlavičce makra chybí parametry. +manifest.macro.compile_failed = Makro { $name } se nepodařilo přeložit. +manifest.macro.sequence_invalid = Makra musí být definována jako mapování názvů na šablony. +manifest.macro.register_failed = Makra manifestu se nepodařilo zaregistrovat. +manifest.macro.not_initialised = Prostředí maker není inicializováno. +manifest.macro.caller_invalid = Volající makra musí být řetězec. +manifest.macro.template_load_failed = Šablonu makra se nepodařilo načíst. +manifest.macro.init_failed = Prostředí maker se nepodařilo inicializovat. +manifest.macro.missing = Makro { $name } chybí. + +# Chyby vzorů glob v manifestu. +manifest.glob.unmatched_brace = Neplatný vzor glob „{ $pattern }“: „{ $character }“ bez protějšku na pozici { $position }. +manifest.glob.invalid_pattern = Neplatný vzor glob „{ $pattern }“: { $detail }. +manifest.glob.unknown_pattern_error = neznámá chyba vzoru. +manifest.glob.io_failed = Glob selhal pro „{ $pattern }“: { $detail }. +manifest.glob.unknown_io_error = neznámá vstupně-výstupní chyba. + +# Chyby mezikódu. +ir.rule_not_found = Pravidlo „{ $rule }“, na které odkazuje cíl „{ $target }“, nebylo nalezeno. +ir.multiple_rules = Cíl „{ $target }“ musí odkazovat právě na jedno pravidlo, obdrženo { $rules }. +ir.empty_rule = Cíl „{ $target }“ musí odkazovat na pravidlo. +ir.duplicate_outputs = Byly zjištěny duplicitní výstupy: { $outputs }. +ir.circular_dependency = Byla zjištěna cyklická závislost: { $cycle }. +ir.action_serialisation = Akci se nepodařilo serializovat: { $details }. +ir.invalid_command = Neplatné vložení v příkazu: { $snippet }. + +# Chyby při generování souborů Ninja. +ninja_gen.missing_action = Chybí akce „{ $id }“, na kterou odkazuje hrana sestavení. +ninja_gen.format = Výstup manifestu Ninja se nepodařilo naformátovat. + +# Ověření vzorů hostitelů. +host_pattern.empty = Vzor hostitele nesmí být prázdný. +host_pattern.contains_scheme = Vzor hostitele „{ $pattern }“ nesmí obsahovat schéma URL. +host_pattern.contains_slash = Vzor hostitele „{ $pattern }“ nesmí obsahovat znak „/“. +host_pattern.missing_suffix = Vzor hostitele „{ $pattern }“ musí obsahovat příponu za „*.“. +host_pattern.empty_label = Vzor hostitele „{ $pattern }“ obsahuje prázdný štítek. +host_pattern.invalid_chars = Vzor hostitele „{ $pattern }“ obsahuje neplatné znaky. +host_pattern.invalid_label_edge = Štítky vzoru hostitele „{ $pattern }“ nesmějí začínat ani končit znakem „-“. +host_pattern.label_too_long = Vzor hostitele „{ $pattern }“ obsahuje štítek delší než 63 znaků. +host_pattern.too_long = Vzor hostitele „{ $pattern }“ překračuje limit 255 znaků. + +# Síťová zásada. +network_policy.scheme.empty = Schéma nesmí být prázdné. +network_policy.scheme.invalid = Schéma „{ $scheme }“ obsahuje neplatné znaky. +network_policy.allowlist.empty = Seznam povolených hostitelů nesmí být prázdný. +network_policy.scheme.not_allowed = Schéma „{ $scheme }“ není povoleno. +network_policy.missing_host = V adrese URL chybí hostitel. +network_policy.host.blocked = Hostitel „{ $host }“ je zásadou blokován. +network_policy.host.not_allowlisted = Hostitel „{ $host }“ není na seznamu povolených. + +# Konfigurace standardní knihovny. +stdlib.config.default_fetch_cache_invalid = Výchozí cesta mezipaměti fetch musí být relativní. +stdlib.config.default_which_cache_invalid = Výchozí kapacita mezipaměti which musí být kladná. +stdlib.config.workspace_root_absolute = Kořenová cesta pracovního prostoru musí být absolutní. +stdlib.config.fetch_response_limit_positive = Limit odpovědi fetch musí být kladný. +stdlib.config.command_output_limit_positive = Limit zachyceného výstupu příkazů musí být kladný. +stdlib.config.command_stream_limit_positive = Limit proudu příkazů musí být kladný. +stdlib.config.which_cache_capacity_positive = Kapacita mezipaměti which musí být kladná. +stdlib.config.skip_dir_empty = Položky přeskakovaných adresářů nesmějí být prázdné. +stdlib.config.skip_dir_navigation = Položky přeskakovaných adresářů nesmějí obsahovat „..“. +stdlib.config.skip_dir_separator = Položky přeskakovaných adresářů nesmějí obsahovat oddělovače cest. +stdlib.config.fetch_cache_empty = Cesta mezipaměti fetch nesmí být prázdná. +stdlib.config.fetch_cache_not_relative = Cesta mezipaměti fetch musí být relativní, obdrženo { $path }. +stdlib.config.fetch_cache_escapes = Cesta mezipaměti fetch nesmí opustit pracovní prostor: { $path }. +stdlib.config.open_workspace_root = Aktuální adresář se nepodařilo otevřít jako kořen pracovního prostoru stdlib. +stdlib.config.resolve_cwd = Aktuální adresář se nepodařilo určit jako kořen pracovního prostoru stdlib. +stdlib.config.cwd_non_utf8 = Aktuální adresář obsahuje části, které nejsou v UTF-8: { $path }. + +# Diagnostika pomocníka fetch. +stdlib.fetch.url_invalid = Neplatná adresa URL „{ $url }“: { $details }. +stdlib.fetch.disallowed = Adresa URL „{ $url }“ není povolena: { $details }. +stdlib.fetch.failed = Z adresy „{ $url }“ se nepodařilo stáhnout data: { $details }. +stdlib.fetch.cache_read_failed = Položku mezipaměti „{ $name }“ se nepodařilo přečíst: { $details }. +stdlib.fetch.cache_open_failed = Položku mezipaměti „{ $name }“ se nepodařilo otevřít: { $details }. +stdlib.fetch.response_read_failed = Odpověď z „{ $url }“ se nepodařilo přečíst: { $details }. +stdlib.fetch.response_buffer_overflow = Přetečení vyrovnávací paměti při čtení „{ $url }“. +stdlib.fetch.cache_write_failed = Mezipaměť pro „{ $url }“ se nepodařilo zapsat: { $details }. +stdlib.fetch.response_limit_exceeded = Odpověď z „{ $url }“ překročila limit { $limit } bajtů. +stdlib.fetch.cache_limit_exceeded = Odpověď „{ $name }“ v mezipaměti překročila limit { $limit } bajtů. +stdlib.fetch.io_failed = Akce „{ $action }“ selhala pro { $path }: { $details }. +stdlib.fetch.action.sync_cache = synchronizace mezipaměti fetch +stdlib.fetch.action.create_cache_dir = vytvoření adresáře mezipaměti fetch +stdlib.fetch.action.open_cache_dir = otevření adresáře mezipaměti fetch +stdlib.fetch.action.stat_cache = zjištění údajů o položce mezipaměti fetch +stdlib.fetch.action.open_cache_entry = otevření položky mezipaměti fetch + +# Diagnostika pomocníka pro příkazy. +stdlib.command.location = příkaz „{ $command }“ v šabloně „{ $template }“ +stdlib.command.spawn_failed = { $location } se nepodařilo spustit: { $details }. +stdlib.command.io_failed = { $location } selhal: { $details }. +stdlib.command.closed_input_early = Vstup se uzavřel dříve, než byl zápis do příkazu dokončen. +stdlib.command.broken_pipe = Přerušená roura při běhu { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } byl ukončen signálem. +stdlib.command.exited_with_status = { $location } skončil se stavem { $status }. +stdlib.command.output_limit_exceeded = { $location } překročil limit { $mode } ve výši { $limit } bajtů pro { $stream }. +stdlib.command.timeout = { $location } překročil časový limit { $seconds } s. +stdlib.command.exit_status_suffix = (návratový kód { $status }) +stdlib.command.signal_suffix = (ukončeno signálem) +stdlib.command.shell.empty = Příkaz shellu nesmí být prázdný. +stdlib.command.grep.empty_pattern = Vzor pro grep nesmí být prázdný. +stdlib.command.grep.flags_not_string = Přepínače grepu musí být řetězce. +stdlib.command.quote.invalid = Argument { $arg } se nepodařilo uzavřít do uvozovek: { $details }. +stdlib.command.quote.line_break = Argumenty obsahující návrat vozíku nebo konec řádku nelze bezpečně uzavřít do uvozovek. +stdlib.command.input_undefined = Vstupní hodnota není definována. +stdlib.command.tempfile.root_required = Pro vytváření dočasných souborů příkazů je nutný kořen pracovního prostoru. +stdlib.command.tempfile.create_failed = Dočasný soubor příkazu se nepodařilo vytvořit: { $details }. +stdlib.command.options.invalid_utf8 = Klíč volby příkazu musí být platné UTF-8. +stdlib.command.option.mode_not_string = Režim výstupu musí být řetězec. +stdlib.command.options.invalid_type = Volby příkazu musí být objekt. +stdlib.command.output.mode_unsupported = Nepodporovaný režim výstupu „{ $mode }“. +stdlib.command.output.mode.capture = zachytávání +stdlib.command.output.mode.streaming = proudové zpracování +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Diagnostika pomocníka pro cesty. +stdlib.path.io.failed = Akce „{ $action }“ selhala pro { $path } ({ $label }). +stdlib.path.io.failed_with_detail = Akce „{ $action }“ selhala pro { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = Akce „{ $action }“ selhala pro { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = nenalezeno +stdlib.path.io.permission_denied = přístup odepřen +stdlib.path.io.already_exists = již existuje +stdlib.path.io.invalid_input = neplatný vstup +stdlib.path.io.invalid_data = neplatná data +stdlib.path.io.timed_out = vypršel časový limit +stdlib.path.io.interrupted = přerušeno +stdlib.path.io.would_block = došlo by k zablokování +stdlib.path.io.write_zero = zapsáno nula bajtů +stdlib.path.io.unexpected_eof = neočekávaný konec souboru +stdlib.path.io.broken_pipe = přerušená roura +stdlib.path.io.connection_refused = spojení odmítnuto +stdlib.path.io.connection_reset = spojení resetováno +stdlib.path.io.connection_aborted = spojení přerušeno +stdlib.path.io.not_connected = bez spojení +stdlib.path.io.addr_in_use = adresa se již používá +stdlib.path.io.addr_not_available = adresa není dostupná +stdlib.path.io.out_of_memory = došla paměť +stdlib.path.io.unsupported = nepodporováno +stdlib.path.io.file_too_large = soubor je příliš velký +stdlib.path.io.resource_busy = prostředek je zaneprázdněn +stdlib.path.io.executable_busy = spustitelný soubor je zaneprázdněn +stdlib.path.io.deadlock = uváznutí +stdlib.path.io.crosses_devices = překračuje hranici zařízení +stdlib.path.io.too_many_links = příliš mnoho odkazů +stdlib.path.io.invalid_filename = neplatný název souboru +stdlib.path.io.arg_list_too_long = seznam argumentů je příliš dlouhý +stdlib.path.io.stale_handle = zastaralý popisovač síťového souboru +stdlib.path.io.storage_full = úložiště je plné +stdlib.path.io.not_seekable = nelze v něm nastavovat pozici +stdlib.path.io.network_down = síť je mimo provoz +stdlib.path.io.network_unreachable = síť je nedosažitelná +stdlib.path.io.host_unreachable = hostitel je nedosažitelný +stdlib.path.io.other = vstupně-výstupní chyba +stdlib.path.action.canonicalize = kanonizace +stdlib.path.action.open_directory = otevření adresáře +stdlib.path.action.stat = zjištění údajů +stdlib.path.action.read = čtení +stdlib.path.action.open_file = otevření souboru +stdlib.path.with_suffix.empty_separator = with_suffix vyžaduje neprázdný oddělovač. +stdlib.path.relative_to.mismatch = { $path } není relativní vůči { $root }. +stdlib.path.expanduser.unsupported = Rozvoj znaku ~ pro konkrétního uživatele není podporován. +stdlib.path.expanduser.no_home = Znak ~ nelze rozvinout: není nastavena žádná proměnná prostředí domovského adresáře. +stdlib.path.contents.unsupported_encoding = Nepodporované kódování „{ $encoding }“. +stdlib.path.hash.unsupported_algorithm = Nepodporovaný hashovací algoritmus „{ $algorithm }“. +stdlib.path.hash.unsupported_algorithm_legacy = Nepodporovaný hashovací algoritmus „{ $algorithm }“ (zapněte funkci „{ $feature }“). + +# Diagnostika pomocníků pro kolekce. +stdlib.collections.flatten.expected_sequence = flatten očekával prvky posloupnosti, ale nalezl { $kind }. +stdlib.collections.group_by.empty_attribute = group_by vyžaduje neprázdný atribut. +stdlib.collections.group_by.unresolved = group_by nedokázal najít „{ $attr }“ u prvku typu { $kind }. + +# Diagnostika pomocníků pro čas. +stdlib.time.offset.invalid = Posun now „{ $offset }“ je neplatný: očekáváno „+HH:MM[:SS]“ nebo „Z“. +stdlib.time.timedelta.overflow = Přetečení timedelta při přičítání složky { $component }. +stdlib.time.label.weeks = týdny +stdlib.time.label.days = dny +stdlib.time.label.hours = hodiny +stdlib.time.label.minutes = minuty +stdlib.time.label.seconds = sekundy +stdlib.time.label.milliseconds = milisekundy +stdlib.time.label.microseconds = mikrosekundy +stdlib.time.label.nanoseconds = nanosekundy + +# Diagnostika pomocníka which. +stdlib.which.not_found = [netsuke::jinja::which::not_found] příkaz „{ $command }“ nebyl nalezen po prohledání { $count } položek proměnné PATH. Náhled: { $preview } +stdlib.which.not_found.hint.cwd_auto = Prázdné části proměnné PATH se ignorují; pomocí cwd_mode="auto" zahrnete pracovní adresář. +stdlib.which.not_found.hint.cwd_always = Nastavte cwd_mode="always", chcete-li zahrnout aktuální adresář. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] příkaz „{ $command }“ v „{ $path }“ chybí nebo není spustitelný. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = Položka č. { $index } proměnné PATH obsahuje znaky, které nejsou v UTF-8; Netsuke vyžaduje cesty v UTF-8. +stdlib.which.command.empty = which vyžaduje neprázdný řetězec. +stdlib.which.cwd_mode.invalid = cwd_mode musí být „auto“, „always“ nebo „never“, obdrženo „{ $mode }“. +stdlib.which.cwd.resolve_failed = Aktuální adresář se nepodařilo určit: { $details }. +stdlib.which.cwd.non_utf8 = Aktuální adresář obsahuje části, které nejsou v UTF-8. +stdlib.which.canonicalize_failed = Cestu „{ $path }“ se nepodařilo kanonizovat: { $details }. +stdlib.which.is_executable = Nepodařilo se zjistit, zda je „{ $path }“ spustitelný: { $details }. +stdlib.which.canonicalize_non_utf8 = Kanonická cesta obsahuje části, které nejsou v UTF-8. +stdlib.which.workspace_non_utf8 = Cesta pracovního prostoru obsahuje při hledání příkazu „{ $command }“ části, které nejsou v UTF-8: { $path }. +stdlib.which.walkdir_error = Chyba při procházení pracovního prostoru během hledání příkazu: { $details }. + +# Registrace standardní knihovny. +stdlib.register.open_dir = Aktuální adresář se nepodařilo otevřít pro registraci stdlib. +stdlib.register.resolve_dir = Aktuální adresář se nepodařilo určit pro registraci stdlib. +stdlib.register.dir_non_utf8 = Aktuální adresář obsahuje části, které nejsou v UTF-8: { $path }. + +# Hlášení stavu v přístupném režimu výstupu. +status.state.pending = čeká +status.state.running = probíhá +status.state.done = hotovo +status.state.failed = selhalo +status.stage.label = Fáze { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Úloha { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Čtení souboru manifestu +status.stage.initial_yaml_parsing = Zpracování dokumentu YAML +status.stage.template_expansion = Rozvíjení direktiv šablon +status.stage.final_rendering = Deserializace a vykreslení hodnot manifestu +status.stage.ir_generation_validation = Sestavení a ověření grafu závislostí +status.stage.ninja_synthesis = Sestavení plánu Ninja +status.stage.ninja_synthesis_execute = Sestavení plánu Ninja a spuštění { $tool } +status.stage.graph_rendering = Vykreslování artefaktu grafu +status.stage.graph_rendering_with_tool = Vykreslování { $tool } +status.complete = { $tool }: dokončeno. +status.timing.summary_header = Souhrn časů podle fází: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Celkový čas zpracování: { $duration } +status.tool.build = Sestavení +status.tool.clean = Vyčištění +status.tool.graph = Graf +status.tool.graph_html = Graf (HTML) +status.tool.generate = Generování + +# Texty vykreslování grafu do HTML. +graph.html.title = Graf sestavení Netsuke +graph.html.heading = Graf sestavení Netsuke +graph.html.description = Graf sestavení vykreslený nástrojem Netsuke +graph.html.outline.summary = Cíle a závislosti (textový přehled) +graph.html.outline.no_inputs = Žádné vstupy +graph.html.noscript.notice = JavaScript je vypnutý. Textový přehled výše obsahuje celý graf; níže následuje zdroj DOT. + +# Sémantické předpony přístupného výstupu. +semantic.prefix.error = Chyba: +semantic.prefix.warning = Varování: +semantic.prefix.success = Úspěch: +semantic.prefix.info = Informace: +semantic.prefix.timing = Čas: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Příklady množných tvarů pro překladatele. +# Čeština používá kategorie CLDR `one`, `few`, `many` a `other`; `few` pokrývá +# 2–4 a `many` desetinná čísla. +example.files_processed = { $count -> + [one] Zpracován { $count } soubor. + [few] Zpracovány { $count } soubory. + [many] Zpracováno { $count } souboru. + *[other] Zpracováno { $count } souborů. +} + +example.errors_found = { $count -> + [0] Nebyly nalezeny žádné chyby. + [one] Nalezena { $count } chyba. + [few] Nalezeny { $count } chyby. + [many] Nalezeno { $count } chyby. + *[other] Nalezeno { $count } chyb. +} diff --git a/locales/cy/messages.ftl b/locales/cy/messages.ftl new file mode 100644 index 000000000..eef85f00a --- /dev/null +++ b/locales/cy/messages.ftl @@ -0,0 +1,405 @@ +# Adnoddau lleoleiddio ar gyfer llinell orchymyn Netsuke. + +cli.about = Mae Netsuke yn trosi maniffestau YAML + Jinja yn gynlluniau adeiladu Ninja. +cli.long_about = Mae Netsuke yn trawsnewid maniffestau YAML + Jinja yn graffiau Ninja atgynhyrchadwy ac yn rhedeg Ninja gyda rhagosodiadau diogel. +cli.usage = { $usage } + +# Testun cymorth y dewisiadau cyffredinol. +cli.flag.file.help = Llwybr y ffeil faniffest Netsuke i'w defnyddio. +cli.flag.directory.help = Rhedeg fel petai wedi cychwyn yn y cyfeiriadur hwn. +cli.flag.config.help = Llwybr ffeil ffurfweddu, gan osgoi'r chwilio awtomatig. +cli.flag.jobs.help = Gosod nifer y tasgau adeiladu cyfochrog. +cli.flag.verbose.help = Galluogi cofnodi diagnostig manwl a chrynodebau amser wrth orffen. +cli.flag.locale.help = Tag iaith ar gyfer testun y llinell orchymyn (er enghraifft: en-US, cy). +cli.flag.fetch_allow_scheme.help = Cynlluniau URL ychwanegol a ganiateir i'r cynorthwyydd fetch. +cli.flag.fetch_allow_host.help = Enwau gwesteiwyr a ganiateir pan fo'r gwrthod rhagosodedig ymlaen. +cli.flag.fetch_block_host.help = Enwau gwesteiwyr a rwystrir bob amser, hyd yn oed os caniateir hwy mewn man arall. +cli.flag.fetch_default_deny.help = Gwrthod pob gwesteiwr yn rhagosodedig; caniatáu'r rhestr a ddatganwyd yn unig. +cli.flag.json.help = Allbynnu JSON y gall pheiriant ei ddarllen. +cli.flag.no_input.help = Peidio byth â darllen mewnbwn rhyngweithiol. +cli.flag.color.help = Polisi allbwn lliw (auto, always, never). +cli.flag.emoji.help = Polisi emoji (auto, always, never). +cli.flag.progress.help = Polisi dangos cynnydd (auto, always, never). +cli.flag.accessibility.help = Polisi allbwn hygyrch (auto, on, off). +cli.flag.default_targets.help = Targedau adeiladu rhagosodedig pan na nodir yr un. + +# Disgrifiadau'r is-orchmynion. +cli.subcommand.build.about = Adeiladu'r targedau a ddiffinnir yn y maniffest (rhagosodedig). +cli.subcommand.build.long_about = Adeiladu'r targedau y gofynnwyd amdanynt; os na nodir yr un, defnyddir rhagosodiadau'r maniffest. +cli.subcommand.clean.about = Tynnu arteffactau'r adeiladu drwy Ninja. +cli.subcommand.clean.long_about = Creu ffeil Ninja dros dro, yna rhedeg `ninja -t clean`. +cli.subcommand.graph.about = Allbynnu graff dibyniaethau'r adeiladu. DOT yw'r fformat rhagosodedig. +cli.subcommand.graph.long_about = Taflunio'r maniffest Netsuke a ddadansoddwyd yn graff adeiladu canonaidd a'i ysgrifennu fel Graphviz DOT, neu fel tudalen HTML hunangynhwysol gyda `--html`. Defnyddiwch `--output ` i ysgrifennu i ffeil; mae `-` yn ysgrifennu i'r allbwn safonol. +cli.subcommand.generate.about = Creu'r maniffest Ninja heb redeg Ninja. +cli.subcommand.generate.long_about = Ysgrifennu'r maniffest Ninja a gynhyrchwyd i'r allbwn safonol, neu i ffeil a ddewisir gyda `--output`. + +# Testun cymorth dewisiadau'r is-orchymyn build. +cli.subcommand.build.flag.targets.help = Y targedau i'w hadeiladu (defnyddir rhagosodiadau'r maniffest os hepgorir hwy). + +# Testun cymorth dewisiadau'r is-orchymyn graph. +cli.subcommand.graph.flag.html.help = Rendro'r graff fel tudalen HTML hunangynhwysol yn lle DOT. +cli.subcommand.graph.flag.output.help = Ysgrifennu arteffact y graff i FFEIL; defnyddiwch `-` ar gyfer yr allbwn safonol. + +# Testun cymorth dewisiadau'r is-orchymyn generate. +cli.subcommand.generate.flag.output.help = Ysgrifennu'r maniffest Ninja a gynhyrchwyd i FFEIL yn lle'r allbwn safonol. + +# Gwallau dilysu'r llinell orchymyn. +cli.validation.jobs.invalid_number = Nid yw { $value } yn rhif dilys. +cli.validation.jobs.out_of_range = Rhaid i nifer y tasgau fod rhwng { $min } a { $max }. +cli.validation.scheme.empty = Rhaid i'r cynllun beidio â bod yn wag. +cli.validation.scheme.invalid_start = Rhaid i'r cynllun ‘{ $scheme }’ ddechrau â llythyren ASCII. +cli.validation.scheme.invalid = Cynllun annilys: ‘{ $scheme }’. +cli.validation.locale.empty = Rhaid i'r tag iaith beidio â bod yn wag. +cli.validation.locale.invalid = Tag iaith annilys: ‘{ $locale }’. +cli.validation.color.invalid = Polisi lliw annilys: ‘{ $value }’. Dewisiadau dilys: auto, always, never. +cli.validation.emoji.invalid = Polisi emoji annilys: ‘{ $value }’. Dewisiadau dilys: auto, always, never. +cli.validation.progress.invalid = Polisi cynnydd annilys: ‘{ $value }’. Dewisiadau dilys: auto, always, never. +cli.validation.accessibility.invalid = Polisi hygyrchedd annilys: ‘{ $value }’. Dewisiadau dilys: auto, on, off. +cli.validation.config.expected_object = Disgwylid i werthoedd y llinell orchymyn gyfresoli'n wrthrych, ond cafwyd { $value }. + +# Negeseuon gwall Clap. +clap-error-missing-argument = Ymresymiad gofynnol ar goll: { $argument } +clap-error-missing-subcommand = Is-orchymyn ar goll. Dewisiadau sydd ar gael: { $valid_subcommands } +clap-error-unknown-argument = Ymresymiad anhysbys: { $argument } +clap-error-invalid-value = Gwerth annilys ar gyfer { $argument }: { $value } +clap-error-invalid-subcommand = Is-orchymyn anhysbys: { $subcommand } +# Sylwer: mae geiriad value-validation yn wahanol i invalid-value er mwyn +# gwahaniaethu rhwng methiannau dilyswyr pwrpasol (ErrorKind::ValueValidation) +# a gwrthdaro mathau (ErrorKind::InvalidValue). +clap-error-value-validation = Methodd y dilysu ar gyfer { $argument }: { $value } + +# Gwallau a chyd-destun wrth redeg. +runner.manifest.not_found = Ni chafwyd hyd i'r maniffest ‘{ $manifest_name }’ yn { $directory }. +runner.manifest.not_found.help = Sicrhewch fod y maniffest yn bodoli, neu rhowch `--file` gyda'r llwybr cywir. +runner.manifest.path_missing_name = Nid oes enw ffeil yn llwybr y maniffest ‘{ $path }’. +runner.manifest.path_utf8 = Nid yw llwybr y maniffest ‘{ $path }’ yn UTF-8 dilys. +runner.manifest.directory_utf8 = Nid yw llwybr cyfeiriadur y maniffest ‘{ $path }’ yn UTF-8 dilys. +runner.manifest.directory_label = cyfeiriadur `{ $directory }` +runner.manifest.current_directory_label = y cyfeiriadur cyfredol +runner.context.network_policy = Methwyd â llunio'r polisi rhwydwaith. +runner.context.load_manifest = Methwyd â llwytho'r maniffest o { $path }. +runner.context.serialise_manifest = Methwyd â chyfresoli'r maniffest. +runner.context.build_graph = Methwyd â llunio graff o'r maniffest. +runner.context.generate_ninja = Methwyd â chreu'r maniffest Ninja. +runner.context.render_graph = Methwyd â rendro arteffact y graff. + +runner.io.create_temp_file = Methwyd â chreu'r ffeil Ninja dros dro. +runner.io.write_temp_ninja = Methwyd ag ysgrifennu i'r ffeil Ninja dros dro. +runner.io.flush_temp_ninja = Methwyd â gwagio byffer y ffeil Ninja dros dro. +runner.io.sync_temp_ninja = Methwyd â chydamseru'r ffeil Ninja dros dro. +runner.io.create_parent_dir = Methwyd â chreu'r cyfeiriadur rhiant { $path }. +runner.io.create_ninja_file = Methwyd â chreu'r ffeil Ninja yn { $path }. +runner.io.write_ninja_file = Methwyd ag ysgrifennu i'r ffeil Ninja yn { $path }. +runner.io.flush_ninja_file = Methwyd â gwagio byffer y ffeil Ninja yn { $path }. +runner.io.sync_ninja_file = Methwyd â chydamseru'r ffeil Ninja yn { $path }. +runner.io.open_ambient_dir = Methwyd ag agor y cyfeiriadur amgylchynol. +runner.io.no_existing_ancestor = Nid oes cyfeiriadur uwch yn bodoli ar gyfer { $path }. +runner.io.derive_relative_path = Methwyd â deillio llwybr Ninja cymharol. +runner.io.non_utf8_path = Ni chefnogir llwybrau nad ydynt yn UTF-8 (llwybr: { $path }). +runner.io.write_stdout = Methwyd ag ysgrifennu'r maniffest Ninja i'r allbwn safonol. +runner.io.flush_stdout = Methwyd â gwagio byffer yr allbwn safonol. + +# Diagnosteg y maniffest. +manifest.parse = Methodd dadansoddiad y maniffest. +manifest.structure_error = Gwall strwythur yn y maniffest yn { $name }: { $details } +manifest.yaml.parse = Gwall dadansoddi YAML ar linell { $line }, colofn { $column }: { $details } +manifest.yaml.label = YAML annilys +manifest.yaml.hint.tabs = Nid yw YAML yn caniatáu tabiau; defnyddiwch fylchau i fewnoli. +manifest.yaml.hint.list_item = Rhaid i eitemau rhestr YAML ddechrau â ‘-’ a chael eu mewnoli'n gywir. +manifest.yaml.hint.expected_colon = Mae hyn yn edrych fel cofnod mapio; mae ‘:’ ar goll ar ôl yr allwedd. +manifest.yaml.hint.mapping_values = Mae mapiau YAML angen gwerth ar ôl ‘:’ (neu floc nythog). +manifest.yaml.hint.invalid_token = Mae'r tocyn YAML yn annilys neu'n annisgwyl. +manifest.yaml.hint.escape = Diangwch y slaesau ôl neu dynnwch y dilyniannau dianc annilys. +manifest.env.missing = Nid yw'r newidyn amgylchedd gofynnol ‘{ $name }’ wedi'i osod. +manifest.env.invalid_utf8 = Mae'r newidyn amgylchedd ‘{ $name }’ yn cynnwys UTF-8 annilys. +manifest.vars.not_object = Rhaid i `vars` y maniffest fod yn fap neu'n wrthrych. +manifest.read_failed = Methwyd â darllen y maniffest o { $path }. +manifest.resolve_workspace_root = Methwyd â phennu gwraidd y gweithle. +manifest.workspace_non_utf8 = Nid yw llwybr gwraidd y gweithle ‘{ $path }’ yn UTF-8 dilys. +manifest.path_non_utf8 = Nid yw llwybr y maniffest ‘{ $manifest }’ yn UTF-8 dilys: { $path }. +manifest.path_missing_name = Nid oes enw ffeil yn llwybr y maniffest ‘{ $path }’. +manifest.open_workspace_failed = Methwyd ag agor y gweithle { $workspace } ar gyfer y maniffest { $manifest }. +manifest.foreach.not_iterable = Ni ellir iteru dros y mynegiad `foreach`. +manifest.foreach.serialise_item = Methwyd â chyfresoli eitem `foreach`. +manifest.when.empty = Rhaid i'r mynegiad `when` beidio â bod yn wag. +manifest.when.eval_error = Methwyd â gwerthuso'r mynegiad `when` ‘{ $expr }’. +manifest.when.template_error = Methwyd â rendro'r templed `when` ‘{ $expr }’. +manifest.target.vars_not_object = Rhaid i `vars` y targed fod yn wrthrych, ond cafwyd { $value }. +manifest.vars.entry_not_object = Rhaid i gofnod `vars` y maniffest fod yn wrthrych. +manifest.field_not_string = Rhaid i'r maes ‘{ $field }’ fod yn llinyn. +manifest.expression.parse_error = Methwyd â dadansoddi'r mynegiad { $name }. +manifest.expression.eval_error = Methwyd â gwerthuso'r mynegiad { $name }. + +# Diagnosteg macros y maniffest. +manifest.macro.signature_missing_identifier = Mae dynodydd ar goll o lofnod y macro. +manifest.macro.signature_missing_params = Mae paramedrau ar goll o lofnod y macro. +manifest.macro.compile_failed = Methwyd â throsi'r macro { $name }. +manifest.macro.sequence_invalid = Rhaid diffinio macros fel map o enwau i dempledi. +manifest.macro.register_failed = Methwyd â chofrestru macros y maniffest. +manifest.macro.not_initialised = Nid yw amgylchedd y macros wedi'i baratoi. +manifest.macro.caller_invalid = Rhaid i alwr y macro fod yn llinyn. +manifest.macro.template_load_failed = Methwyd â llwytho templed y macro. +manifest.macro.init_failed = Methwyd â pharatoi amgylchedd y macros. +manifest.macro.missing = Mae'r macro { $name } ar goll. + +# Gwallau patrymau glob y maniffest. +manifest.glob.unmatched_brace = Patrwm glob annilys ‘{ $pattern }’: nid oes pâr i ‘{ $character }’ yn safle { $position }. +manifest.glob.invalid_pattern = Patrwm glob annilys ‘{ $pattern }’: { $detail }. +manifest.glob.unknown_pattern_error = gwall patrwm anhysbys. +manifest.glob.io_failed = Methodd glob ar gyfer ‘{ $pattern }’: { $detail }. +manifest.glob.unknown_io_error = gwall mewnbwn/allbwn anhysbys. + +# Gwallau'r cynrychioliad canolradd. +ir.rule_not_found = Ni chafwyd hyd i'r rheol ‘{ $rule }’ y cyfeirir ati gan y targed ‘{ $target }’. +ir.multiple_rules = Rhaid i'r targed ‘{ $target }’ gyfeirio at un rheol yn unig, ond cafwyd { $rules }. +ir.empty_rule = Rhaid i'r targed ‘{ $target }’ gyfeirio at reol. +ir.duplicate_outputs = Canfuwyd allbynnau dyblyg: { $outputs }. +ir.circular_dependency = Canfuwyd dibyniaeth gylchol: { $cycle }. +ir.action_serialisation = Methwyd â chyfresoli'r weithred: { $details }. +ir.invalid_command = Mewnosodiad annilys yn y gorchymyn: { $snippet }. + +# Gwallau cynhyrchu Ninja. +ninja_gen.missing_action = Mae'r weithred ‘{ $id }’ y cyfeirir ati gan ymyl adeiladu ar goll. +ninja_gen.format = Methwyd â fformatio allbwn y maniffest Ninja. + +# Dilysu patrymau gwesteiwyr. +host_pattern.empty = Rhaid i'r patrwm gwesteiwr beidio â bod yn wag. +host_pattern.contains_scheme = Rhaid i'r patrwm gwesteiwr ‘{ $pattern }’ beidio â chynnwys cynllun URL. +host_pattern.contains_slash = Rhaid i'r patrwm gwesteiwr ‘{ $pattern }’ beidio â chynnwys ‘/’. +host_pattern.missing_suffix = Rhaid i'r patrwm gwesteiwr ‘{ $pattern }’ gynnwys ôl-ddodiad ar ôl ‘*.’. +host_pattern.empty_label = Mae'r patrwm gwesteiwr ‘{ $pattern }’ yn cynnwys label gwag. +host_pattern.invalid_chars = Mae'r patrwm gwesteiwr ‘{ $pattern }’ yn cynnwys nodau annilys. +host_pattern.invalid_label_edge = Rhaid i labeli'r patrwm gwesteiwr ‘{ $pattern }’ beidio â dechrau na gorffen â ‘-’. +host_pattern.label_too_long = Mae'r patrwm gwesteiwr ‘{ $pattern }’ yn cynnwys label hwy na 63 nod. +host_pattern.too_long = Mae'r patrwm gwesteiwr ‘{ $pattern }’ yn fwy na'r terfyn o 255 nod. + +# Polisi'r rhwydwaith. +network_policy.scheme.empty = Rhaid i'r cynllun beidio â bod yn wag. +network_policy.scheme.invalid = Mae'r cynllun ‘{ $scheme }’ yn cynnwys nodau annilys. +network_policy.allowlist.empty = Rhaid i'r rhestr gwesteiwyr a ganiateir beidio â bod yn wag. +network_policy.scheme.not_allowed = Ni chaniateir y cynllun ‘{ $scheme }’. +network_policy.missing_host = Mae gwesteiwr ar goll o'r URL. +network_policy.host.blocked = Mae'r gwesteiwr ‘{ $host }’ wedi'i rwystro gan y polisi. +network_policy.host.not_allowlisted = Nid yw'r gwesteiwr ‘{ $host }’ ar y rhestr a ganiateir. + +# Ffurfweddu'r llyfrgell safonol. +stdlib.config.default_fetch_cache_invalid = Rhaid i lwybr rhagosodedig storfa fetch fod yn gymharol. +stdlib.config.default_which_cache_invalid = Rhaid i gynhwysedd rhagosodedig storfa which fod yn bositif. +stdlib.config.workspace_root_absolute = Rhaid i lwybr gwraidd y gweithle fod yn absoliwt. +stdlib.config.fetch_response_limit_positive = Rhaid i derfyn ymateb fetch fod yn bositif. +stdlib.config.command_output_limit_positive = Rhaid i derfyn dal allbwn gorchmynion fod yn bositif. +stdlib.config.command_stream_limit_positive = Rhaid i derfyn ffrwd y gorchmynion fod yn bositif. +stdlib.config.which_cache_capacity_positive = Rhaid i gynhwysedd storfa which fod yn bositif. +stdlib.config.skip_dir_empty = Rhaid i gofnodion y cyfeiriaduron a hepgorir beidio â bod yn wag. +stdlib.config.skip_dir_navigation = Rhaid i gofnodion y cyfeiriaduron a hepgorir beidio â chynnwys ‘..’. +stdlib.config.skip_dir_separator = Rhaid i gofnodion y cyfeiriaduron a hepgorir beidio â chynnwys gwahanyddion llwybr. +stdlib.config.fetch_cache_empty = Rhaid i lwybr storfa fetch beidio â bod yn wag. +stdlib.config.fetch_cache_not_relative = Rhaid i lwybr storfa fetch fod yn gymharol, ond cafwyd { $path }. +stdlib.config.fetch_cache_escapes = Rhaid i lwybr storfa fetch beidio â gadael y gweithle: { $path }. +stdlib.config.open_workspace_root = Methwyd ag agor y cyfeiriadur cyfredol fel gwraidd gweithle stdlib. +stdlib.config.resolve_cwd = Methwyd â phennu'r cyfeiriadur cyfredol fel gwraidd gweithle stdlib. +stdlib.config.cwd_non_utf8 = Mae'r cyfeiriadur cyfredol yn cynnwys rhannau nad ydynt yn UTF-8: { $path }. + +# Diagnosteg y cynorthwyydd fetch. +stdlib.fetch.url_invalid = URL annilys ‘{ $url }’: { $details }. +stdlib.fetch.disallowed = Ni chaniateir yr URL ‘{ $url }’: { $details }. +stdlib.fetch.failed = Methwyd â nôl ‘{ $url }’: { $details }. +stdlib.fetch.cache_read_failed = Methwyd â darllen cofnod y storfa ‘{ $name }’: { $details }. +stdlib.fetch.cache_open_failed = Methwyd ag agor cofnod y storfa ‘{ $name }’: { $details }. +stdlib.fetch.response_read_failed = Methwyd â darllen yr ymateb o ‘{ $url }’: { $details }. +stdlib.fetch.response_buffer_overflow = Gorlifodd y byffer wrth ddarllen ‘{ $url }’. +stdlib.fetch.cache_write_failed = Methwyd ag ysgrifennu'r storfa ar gyfer ‘{ $url }’: { $details }. +stdlib.fetch.response_limit_exceeded = Aeth yr ymateb o ‘{ $url }’ dros y terfyn o { $limit } beit. +stdlib.fetch.cache_limit_exceeded = Aeth yr ymateb a storiwyd ‘{ $name }’ dros y terfyn o { $limit } beit. +stdlib.fetch.io_failed = Methodd y weithred ‘{ $action }’ ar gyfer { $path }: { $details }. +stdlib.fetch.action.sync_cache = cydamseru storfa fetch +stdlib.fetch.action.create_cache_dir = creu cyfeiriadur storfa fetch +stdlib.fetch.action.open_cache_dir = agor cyfeiriadur storfa fetch +stdlib.fetch.action.stat_cache = darllen manylion cofnod storfa fetch +stdlib.fetch.action.open_cache_entry = agor cofnod storfa fetch + +# Diagnosteg y cynorthwyydd gorchmynion. +stdlib.command.location = y gorchymyn ‘{ $command }’ yn y templed ‘{ $template }’ +stdlib.command.spawn_failed = Methwyd â chychwyn { $location }: { $details }. +stdlib.command.io_failed = Methodd { $location }: { $details }. +stdlib.command.closed_input_early = Caeodd y mewnbwn cyn gorffen ysgrifennu i'r gorchymyn. +stdlib.command.broken_pipe = Torrodd y bibell wrth redeg { $location }: { $details }. +stdlib.command.terminated_by_signal = Terfynwyd { $location } gan signal. +stdlib.command.exited_with_status = Gorffennodd { $location } gyda'r statws { $status }. +stdlib.command.output_limit_exceeded = Aeth { $location } dros derfyn { $mode } o { $limit } beit ar gyfer { $stream }. +stdlib.command.timeout = Aeth { $location } dros y terfyn amser o { $seconds } eiliad. +stdlib.command.exit_status_suffix = (statws gadael { $status }) +stdlib.command.signal_suffix = (terfynwyd gan signal) +stdlib.command.shell.empty = Rhaid i orchymyn y gragen beidio â bod yn wag. +stdlib.command.grep.empty_pattern = Rhaid i batrwm grep beidio â bod yn wag. +stdlib.command.grep.flags_not_string = Rhaid i faneri grep fod yn llinynnau. +stdlib.command.quote.invalid = Methwyd â rhoi { $arg } mewn dyfynodau: { $details }. +stdlib.command.quote.line_break = Ni ellir rhoi ymresymiadau sy'n cynnwys dychweliad cerbyd neu doriad llinell mewn dyfynodau'n ddiogel. +stdlib.command.input_undefined = Nid yw gwerth y mewnbwn wedi'i ddiffinio. +stdlib.command.tempfile.root_required = Mae angen gwraidd y gweithle i greu ffeiliau gorchymyn dros dro. +stdlib.command.tempfile.create_failed = Methwyd â chreu ffeil dros dro'r gorchymyn: { $details }. +stdlib.command.options.invalid_utf8 = Rhaid i allwedd dewisiad gorchymyn fod yn UTF-8 dilys. +stdlib.command.option.mode_not_string = Rhaid i'r modd allbwn fod yn llinyn. +stdlib.command.options.invalid_type = Rhaid i ddewisiadau'r gorchymyn fod yn wrthrych. +stdlib.command.output.mode_unsupported = Modd allbwn nas cefnogir: ‘{ $mode }’. +stdlib.command.output.mode.capture = dal +stdlib.command.output.mode.streaming = ffrydio +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Diagnosteg y cynorthwyydd llwybrau. +stdlib.path.io.failed = Methodd y weithred ‘{ $action }’ ar gyfer { $path } ({ $label }). +stdlib.path.io.failed_with_detail = Methodd y weithred ‘{ $action }’ ar gyfer { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = Methodd y weithred ‘{ $action }’ ar gyfer { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = heb ei ganfod +stdlib.path.io.permission_denied = caniatâd wedi'i wrthod +stdlib.path.io.already_exists = yn bodoli eisoes +stdlib.path.io.invalid_input = mewnbwn annilys +stdlib.path.io.invalid_data = data annilys +stdlib.path.io.timed_out = amser wedi dod i ben +stdlib.path.io.interrupted = torrwyd ar draws +stdlib.path.io.would_block = byddai'n rhwystro +stdlib.path.io.write_zero = ysgrifennwyd dim beit +stdlib.path.io.unexpected_eof = diwedd ffeil annisgwyl +stdlib.path.io.broken_pipe = pibell wedi torri +stdlib.path.io.connection_refused = gwrthodwyd y cysylltiad +stdlib.path.io.connection_reset = ailosodwyd y cysylltiad +stdlib.path.io.connection_aborted = terfynwyd y cysylltiad +stdlib.path.io.not_connected = heb gysylltu +stdlib.path.io.addr_in_use = cyfeiriad ar waith eisoes +stdlib.path.io.addr_not_available = cyfeiriad ddim ar gael +stdlib.path.io.out_of_memory = cof wedi dod i ben +stdlib.path.io.unsupported = nas cefnogir +stdlib.path.io.file_too_large = ffeil yn rhy fawr +stdlib.path.io.resource_busy = adnodd yn brysur +stdlib.path.io.executable_busy = ffeil weithredadwy yn brysur +stdlib.path.io.deadlock = cloi marw +stdlib.path.io.crosses_devices = yn croesi dyfeisiau +stdlib.path.io.too_many_links = gormod o gysylltiadau +stdlib.path.io.invalid_filename = enw ffeil annilys +stdlib.path.io.arg_list_too_long = rhestr ymresymiadau'n rhy hir +stdlib.path.io.stale_handle = dolen ffeil rwydwaith hen +stdlib.path.io.storage_full = storfa'n llawn +stdlib.path.io.not_seekable = methu gosod safle +stdlib.path.io.network_down = rhwydwaith i lawr +stdlib.path.io.network_unreachable = methu cyrraedd y rhwydwaith +stdlib.path.io.host_unreachable = methu cyrraedd y gwesteiwr +stdlib.path.io.other = gwall mewnbwn/allbwn +stdlib.path.action.canonicalize = canoneiddio +stdlib.path.action.open_directory = agor cyfeiriadur +stdlib.path.action.stat = darllen manylion +stdlib.path.action.read = darllen +stdlib.path.action.open_file = agor ffeil +stdlib.path.with_suffix.empty_separator = Mae with_suffix angen gwahanydd nad yw'n wag. +stdlib.path.relative_to.mismatch = Nid yw { $path } yn gymharol i { $root }. +stdlib.path.expanduser.unsupported = Ni chefnogir ehangu ~ ar gyfer defnyddiwr penodol. +stdlib.path.expanduser.no_home = Ni ellir ehangu ~: nid oes newidyn amgylchedd cyfeiriadur cartref wedi'i osod. +stdlib.path.contents.unsupported_encoding = Amgodiad nas cefnogir: ‘{ $encoding }’. +stdlib.path.hash.unsupported_algorithm = Algorithm stwnsio nas cefnogir: ‘{ $algorithm }’. +stdlib.path.hash.unsupported_algorithm_legacy = Algorithm stwnsio nas cefnogir: ‘{ $algorithm }’ (galluogwch y nodwedd ‘{ $feature }’). + +# Diagnosteg cynorthwywyr y casgliadau. +stdlib.collections.flatten.expected_sequence = Roedd flatten yn disgwyl eitemau dilyniant ond cafodd { $kind }. +stdlib.collections.group_by.empty_attribute = Mae group_by angen priodoledd nad yw'n wag. +stdlib.collections.group_by.unresolved = Methodd group_by â chanfod ‘{ $attr }’ ar eitem o'r math { $kind }. + +# Diagnosteg cynorthwywyr amser. +stdlib.time.offset.invalid = Mae gwrthbwyso now ‘{ $offset }’ yn annilys: disgwylid ‘+HH:MM[:SS]’ neu ‘Z’. +stdlib.time.timedelta.overflow = Gorlifodd timedelta wrth ychwanegu { $component }. +stdlib.time.label.weeks = wythnosau +stdlib.time.label.days = dyddiau +stdlib.time.label.hours = oriau +stdlib.time.label.minutes = munudau +stdlib.time.label.seconds = eiliadau +stdlib.time.label.milliseconds = milieiliadau +stdlib.time.label.microseconds = microeiliadau +stdlib.time.label.nanoseconds = nanoeiliadau + +# Diagnosteg y cynorthwyydd which. +stdlib.which.not_found = [netsuke::jinja::which::not_found] ni chafwyd hyd i'r gorchymyn ‘{ $command }’ ar ôl gwirio { $count } cofnod PATH. Rhagolwg: { $preview } +stdlib.which.not_found.hint.cwd_auto = Anwybyddir segmentau gwag PATH; defnyddiwch cwd_mode="auto" i gynnwys y cyfeiriadur gwaith. +stdlib.which.not_found.hint.cwd_always = Gosodwch cwd_mode="always" i gynnwys y cyfeiriadur cyfredol. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] mae'r gorchymyn ‘{ $command }’ yn ‘{ $path }’ ar goll neu nid yw'n weithredadwy. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = Mae cofnod PATH rhif { $index } yn cynnwys nodau nad ydynt yn UTF-8; mae Netsuke angen llwybrau UTF-8. +stdlib.which.command.empty = Mae which angen llinyn nad yw'n wag. +stdlib.which.cwd_mode.invalid = Rhaid i cwd_mode fod yn ‘auto’, ‘always’ neu ‘never’, ond cafwyd ‘{ $mode }’. +stdlib.which.cwd.resolve_failed = Methwyd â phennu'r cyfeiriadur cyfredol: { $details }. +stdlib.which.cwd.non_utf8 = Mae'r cyfeiriadur cyfredol yn cynnwys rhannau nad ydynt yn UTF-8. +stdlib.which.canonicalize_failed = Methwyd â chanoneiddio ‘{ $path }’: { $details }. +stdlib.which.is_executable = Methwyd â gwirio a yw ‘{ $path }’ yn weithredadwy: { $details }. +stdlib.which.canonicalize_non_utf8 = Mae'r llwybr canonaidd yn cynnwys rhannau nad ydynt yn UTF-8. +stdlib.which.workspace_non_utf8 = Mae llwybr y gweithle'n cynnwys rhannau nad ydynt yn UTF-8 wrth ddatrys y gorchymyn ‘{ $command }’: { $path }. +stdlib.which.walkdir_error = Gwall wrth dramwyo'r gweithle wrth ddatrys y gorchymyn: { $details }. + +# Cofrestru'r llyfrgell safonol. +stdlib.register.open_dir = Methwyd ag agor y cyfeiriadur cyfredol ar gyfer cofrestru stdlib. +stdlib.register.resolve_dir = Methwyd â phennu'r cyfeiriadur cyfredol ar gyfer cofrestru stdlib. +stdlib.register.dir_non_utf8 = Mae'r cyfeiriadur cyfredol yn cynnwys rhannau nad ydynt yn UTF-8: { $path }. + +# Adrodd statws ar gyfer y modd allbwn hygyrch. +status.state.pending = yn aros +status.state.running = ar y gweill +status.state.done = wedi'i gwblhau +status.state.failed = wedi methu +status.stage.label = Cam { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Tasg { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Yn darllen ffeil y maniffest +status.stage.initial_yaml_parsing = Yn dadansoddi'r ddogfen YAML +status.stage.template_expansion = Yn ehangu cyfarwyddiadau'r templedi +status.stage.final_rendering = Yn dadgyfresoli ac yn rendro gwerthoedd y maniffest +status.stage.ir_generation_validation = Yn llunio ac yn dilysu'r graff dibyniaethau +status.stage.ninja_synthesis = Yn saernïo cynllun adeiladu Ninja +status.stage.ninja_synthesis_execute = Yn saernïo cynllun Ninja ac yn rhedeg { $tool } +status.stage.graph_rendering = Yn rendro arteffact y graff +status.stage.graph_rendering_with_tool = Yn rendro { $tool } +status.complete = Cwblhawyd { $tool }. +status.timing.summary_header = Crynodeb amser fesul cam: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Cyfanswm amser y llinell brosesu: { $duration } +status.tool.build = Adeiladu +status.tool.clean = Glanhau +status.tool.graph = Graff +status.tool.graph_html = Graff (HTML) +status.tool.generate = Cynhyrchu + +# Testunau rendrwr HTML y graff. +graph.html.title = Graff adeiladu Netsuke +graph.html.heading = Graff adeiladu Netsuke +graph.html.description = Graff adeiladu a rendrwyd gan Netsuke +graph.html.outline.summary = Targedau a dibyniaethau (amlinelliad testun) +graph.html.outline.no_inputs = Dim mewnbynnau +graph.html.noscript.notice = Mae JavaScript wedi'i analluogi. Yr amlinelliad testun uchod yw'r graff cyfan; daw ffynhonnell DOT ar ei ôl. + +# Rhagddodiaid semantig ar gyfer yr allbwn hygyrch. +semantic.prefix.error = Gwall: +semantic.prefix.warning = Rhybudd: +semantic.prefix.success = Llwyddiant: +semantic.prefix.info = Gwybodaeth: +semantic.prefix.timing = Amser: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Enghreifftiau o ffurfiau lluosog i gyfieithwyr. +# Mae'r Gymraeg yn defnyddio pob un o chwe chategori CLDR: `zero`, `one`, +# `two`, `few` (3), `many` (6) ac `other`, ac mae'r treiglad yn newid rhyngddynt. +example.files_processed = { $count -> + [zero] Ni phroseswyd { $count } ffeil. + [one] Proseswyd { $count } ffeil. + [two] Proseswyd { $count } ffeil. + [few] Proseswyd { $count } ffeil. + [many] Proseswyd { $count } ffeil. + *[other] Proseswyd { $count } ffeil. +} + +example.errors_found = { $count -> + [0] Ni chafwyd hyd i unrhyw wallau. + [one] Cafwyd hyd i { $count } gwall. + [two] Cafwyd hyd i { $count } wall. + [few] Cafwyd hyd i { $count } gwall. + [many] Cafwyd hyd i { $count } gwall. + *[other] Cafwyd hyd i { $count } gwall. +} diff --git a/locales/da/messages.ftl b/locales/da/messages.ftl new file mode 100644 index 000000000..b1e60c95e --- /dev/null +++ b/locales/da/messages.ftl @@ -0,0 +1,397 @@ +# Lokaliseringsressourcer til Netsukes kommandolinje. + +cli.about = Netsuke oversætter YAML- + Jinja-manifester til Ninja-byggeplaner. +cli.long_about = Netsuke omdanner YAML- + Jinja-manifester til reproducerbare Ninja-grafer og kører Ninja med sikre standardindstillinger. +cli.usage = { $usage } + +# Hjælpetekst til globale tilvalg. +cli.flag.file.help = Sti til den Netsuke-manifestfil, der skal bruges. +cli.flag.directory.help = Kør, som om der var startet i denne mappe. +cli.flag.config.help = Sti til en konfigurationsfil, som springer den automatiske søgning over. +cli.flag.jobs.help = Angiv antallet af parallelle byggejob. +cli.flag.verbose.help = Aktivér udførlig diagnostisk logning og tidsopsummeringer ved afslutning. +cli.flag.locale.help = Sprogmærke til kommandolinjens tekster (for eksempel: en-US, da). +cli.flag.fetch_allow_scheme.help = Yderligere URL-skemaer, som fetch-hjælperen må bruge. +cli.flag.fetch_allow_host.help = Værtsnavne, der tillades, når standardafvisning er slået til. +cli.flag.fetch_block_host.help = Værtsnavne, der altid blokeres, også hvis de er tilladt andetsteds. +cli.flag.fetch_default_deny.help = Afvis alle værter som standard; tillad kun den erklærede liste. +cli.flag.json.help = Udskriv maskinlæsbart JSON. +cli.flag.no_input.help = Læs aldrig interaktivt input. +cli.flag.color.help = Politik for farvet output (auto, always, never). +cli.flag.emoji.help = Politik for emoji (auto, always, never). +cli.flag.progress.help = Politik for visning af fremdrift (auto, always, never). +cli.flag.accessibility.help = Politik for tilgængeligt output (auto, on, off). +cli.flag.default_targets.help = Standardmål for bygning, når ingen er angivet. + +# Beskrivelser af underkommandoer. +cli.subcommand.build.about = Byg de mål, der er defineret i manifestet (standard). +cli.subcommand.build.long_about = Byg de ønskede mål; er ingen angivet, bruges manifestets standardmål. +cli.subcommand.clean.about = Fjern byggeartefakter via Ninja. +cli.subcommand.clean.long_about = Generér en midlertidig Ninja-fil, og kør derefter `ninja -t clean`. +cli.subcommand.graph.about = Udskriv byggegrafen over afhængigheder. Standardformatet er DOT. +cli.subcommand.graph.long_about = Omsæt det indlæste Netsuke-manifest til en kanonisk byggegraf, og skriv den som Graphviz DOT eller som en selvstændig HTML-side med `--html`. Brug `--output ` for at skrive til en fil; `-` skriver til stdout. +cli.subcommand.generate.about = Generér Ninja-manifestet uden at køre Ninja. +cli.subcommand.generate.long_about = Skriv det genererede Ninja-manifest til stdout eller til en fil valgt med `--output`. + +# Hjælpetekst til tilvalg for underkommandoen build. +cli.subcommand.build.flag.targets.help = Mål, der skal bygges (bruger manifestets standardmål, hvis udeladt). + +# Hjælpetekst til tilvalg for underkommandoen graph. +cli.subcommand.graph.flag.html.help = Gengiv grafen som en selvstændig HTML-side i stedet for DOT. +cli.subcommand.graph.flag.output.help = Skriv grafartefaktet til FIL; brug `-` for stdout. + +# Hjælpetekst til tilvalg for underkommandoen generate. +cli.subcommand.generate.flag.output.help = Skriv det genererede Ninja-manifest til FIL i stedet for stdout. + +# Valideringsfejl på kommandolinjen. +cli.validation.jobs.invalid_number = { $value } er ikke et gyldigt tal. +cli.validation.jobs.out_of_range = Antallet af job skal ligge mellem { $min } og { $max }. +cli.validation.scheme.empty = Skemaet må ikke være tomt. +cli.validation.scheme.invalid_start = Skemaet "{ $scheme }" skal begynde med et ASCII-bogstav. +cli.validation.scheme.invalid = Ugyldigt skema "{ $scheme }". +cli.validation.locale.empty = Sprogmærket må ikke være tomt. +cli.validation.locale.invalid = Ugyldigt sprogmærke "{ $locale }". +cli.validation.color.invalid = Ugyldig farvepolitik "{ $value }". Gyldige valg: auto, always, never. +cli.validation.emoji.invalid = Ugyldig emojipolitik "{ $value }". Gyldige valg: auto, always, never. +cli.validation.progress.invalid = Ugyldig fremdriftspolitik "{ $value }". Gyldige valg: auto, always, never. +cli.validation.accessibility.invalid = Ugyldig tilgængelighedspolitik "{ $value }". Gyldige valg: auto, on, off. +cli.validation.config.expected_object = Kommandolinjens værdier skulle serialiseres til et objekt, men gav { $value }. + +# Fejlmeddelelser fra Clap. +clap-error-missing-argument = Manglende påkrævet argument: { $argument } +clap-error-missing-subcommand = Manglende underkommando. Tilgængelige valg: { $valid_subcommands } +clap-error-unknown-argument = Ukendt argument: { $argument } +clap-error-invalid-value = Ugyldig værdi til { $argument }: { $value } +clap-error-invalid-subcommand = Ukendt underkommando: { $subcommand } +# Bemærk: value-validation er formuleret anderledes end invalid-value for at +# skelne fejl fra egne validatorer (ErrorKind::ValueValidation) fra +# typekonflikter (ErrorKind::InvalidValue). +clap-error-value-validation = Validering mislykkedes for { $argument }: { $value } + +# Fejl og kontekst fra kørslen. +runner.manifest.not_found = Manifestet "{ $manifest_name }" blev ikke fundet i { $directory }. +runner.manifest.not_found.help = Kontrollér, at manifestet findes, eller angiv `--file` med den rigtige sti. +runner.manifest.path_missing_name = Manifeststien "{ $path }" har intet filnavn. +runner.manifest.path_utf8 = Manifeststien "{ $path }" er ikke gyldig UTF-8. +runner.manifest.directory_utf8 = Stien til manifestmappen "{ $path }" er ikke gyldig UTF-8. +runner.manifest.directory_label = mappen `{ $directory }` +runner.manifest.current_directory_label = den aktuelle mappe +runner.context.network_policy = Netværkspolitikken kunne ikke opbygges. +runner.context.load_manifest = Manifestet i { $path } kunne ikke indlæses. +runner.context.serialise_manifest = Manifestet kunne ikke serialiseres. +runner.context.build_graph = Grafen kunne ikke bygges ud fra manifestet. +runner.context.generate_ninja = Ninja-manifestet kunne ikke genereres. +runner.context.render_graph = Grafartefaktet kunne ikke gengives. + +runner.io.create_temp_file = Den midlertidige Ninja-fil kunne ikke oprettes. +runner.io.write_temp_ninja = Den midlertidige Ninja-fil kunne ikke skrives. +runner.io.flush_temp_ninja = Bufferen for den midlertidige Ninja-fil kunne ikke tømmes. +runner.io.sync_temp_ninja = Den midlertidige Ninja-fil kunne ikke synkroniseres. +runner.io.create_parent_dir = Overmappen { $path } kunne ikke oprettes. +runner.io.create_ninja_file = Ninja-filen i { $path } kunne ikke oprettes. +runner.io.write_ninja_file = Ninja-filen i { $path } kunne ikke skrives. +runner.io.flush_ninja_file = Bufferen for Ninja-filen i { $path } kunne ikke tømmes. +runner.io.sync_ninja_file = Ninja-filen i { $path } kunne ikke synkroniseres. +runner.io.open_ambient_dir = Den omgivende mappe kunne ikke åbnes. +runner.io.no_existing_ancestor = Der findes ingen overordnet mappe for { $path }. +runner.io.derive_relative_path = Den relative Ninja-sti kunne ikke udledes. +runner.io.non_utf8_path = Stier, der ikke er UTF-8, understøttes ikke (sti: { $path }). +runner.io.write_stdout = Ninja-manifestet kunne ikke skrives til stdout. +runner.io.flush_stdout = Bufferen for stdout kunne ikke tømmes. + +# Manifestdiagnostik. +manifest.parse = Parsingen af manifestet mislykkedes. +manifest.structure_error = Strukturfejl i manifestet ved { $name }: { $details } +manifest.yaml.parse = YAML-fejl i linje { $line }, kolonne { $column }: { $details } +manifest.yaml.label = ugyldig YAML +manifest.yaml.hint.tabs = YAML tillader ikke tabulatorer; brug mellemrum til indrykning. +manifest.yaml.hint.list_item = YAML-listeelementer skal begynde med "-" og være korrekt indrykket. +manifest.yaml.hint.expected_colon = Dette ligner et opslag i en tilknytning; der mangler et ":" efter nøglen. +manifest.yaml.hint.mapping_values = YAML-tilknytninger kræver en værdi efter ":" (eller en indrykket blok). +manifest.yaml.hint.invalid_token = YAML-symbolet er ugyldigt eller uventet. +manifest.yaml.hint.escape = Escape omvendte skråstreger, eller fjern ugyldige escape-sekvenser. +manifest.env.missing = Den påkrævede miljøvariabel "{ $name }" er ikke sat. +manifest.env.invalid_utf8 = Miljøvariablen "{ $name }" indeholder ugyldig UTF-8. +manifest.vars.not_object = Manifestets `vars` skal være en tilknytning eller et objekt. +manifest.read_failed = Manifestet i { $path } kunne ikke læses. +manifest.resolve_workspace_root = Roden af arbejdsområdet kunne ikke bestemmes. +manifest.workspace_non_utf8 = Rodstien for arbejdsområdet "{ $path }" er ikke gyldig UTF-8. +manifest.path_non_utf8 = Stien til manifestet "{ $manifest }" er ikke gyldig UTF-8: { $path }. +manifest.path_missing_name = Manifeststien "{ $path }" har intet filnavn. +manifest.open_workspace_failed = Arbejdsområdet { $workspace } kunne ikke åbnes for manifestet { $manifest }. +manifest.foreach.not_iterable = Udtrykket `foreach` kan ikke gennemløbes. +manifest.foreach.serialise_item = Elementet i `foreach` kunne ikke serialiseres. +manifest.when.empty = Udtrykket `when` må ikke være tomt. +manifest.when.eval_error = Udtrykket `when` "{ $expr }" kunne ikke evalueres. +manifest.when.template_error = Skabelonen `when` "{ $expr }" kunne ikke gengives. +manifest.target.vars_not_object = Målets `vars` skal være et objekt, men gav { $value }. +manifest.vars.entry_not_object = Et `vars`-opslag i manifestet skal være et objekt. +manifest.field_not_string = Feltet "{ $field }" skal være en streng. +manifest.expression.parse_error = Udtrykket { $name } kunne ikke indlæses. +manifest.expression.eval_error = Udtrykket { $name } kunne ikke evalueres. + +# Diagnostik for manifestmakroer. +manifest.macro.signature_missing_identifier = Makrosignaturen mangler et navn. +manifest.macro.signature_missing_params = Makrosignaturen mangler parametre. +manifest.macro.compile_failed = Makroen { $name } kunne ikke oversættes. +manifest.macro.sequence_invalid = Makroer skal defineres som en tilknytning fra navne til skabeloner. +manifest.macro.register_failed = Manifestets makroer kunne ikke registreres. +manifest.macro.not_initialised = Makromiljøet er ikke klargjort. +manifest.macro.caller_invalid = Makroens kalder skal være en streng. +manifest.macro.template_load_failed = Makroskabelonen kunne ikke indlæses. +manifest.macro.init_failed = Makromiljøet kunne ikke klargøres. +manifest.macro.missing = Makroen { $name } mangler. + +# Glob-fejl i manifestet. +manifest.glob.unmatched_brace = Ugyldigt glob-mønster "{ $pattern }": "{ $character }" uden modstykke på position { $position }. +manifest.glob.invalid_pattern = Ugyldigt glob-mønster "{ $pattern }": { $detail }. +manifest.glob.unknown_pattern_error = ukendt mønsterfejl. +manifest.glob.io_failed = Glob mislykkedes for "{ $pattern }": { $detail }. +manifest.glob.unknown_io_error = ukendt I/O-fejl. + +# Fejl i den interne repræsentation. +ir.rule_not_found = Reglen "{ $rule }", som målet "{ $target }" henviser til, blev ikke fundet. +ir.multiple_rules = Målet "{ $target }" skal henvise til præcis én regel, men gav { $rules }. +ir.empty_rule = Målet "{ $target }" skal henvise til en regel. +ir.duplicate_outputs = Der blev fundet dublerede output: { $outputs }. +ir.circular_dependency = Der blev fundet en cirkulær afhængighed: { $cycle }. +ir.action_serialisation = Handlingen kunne ikke serialiseres: { $details }. +ir.invalid_command = Ugyldig indsættelse i kommandoen: { $snippet }. + +# Fejl under generering af Ninja. +ninja_gen.missing_action = Handlingen "{ $id }", som en byggekant henviser til, mangler. +ninja_gen.format = Ninja-manifestets output kunne ikke formateres. + +# Validering af værtsmønstre. +host_pattern.empty = Værtsmønsteret må ikke være tomt. +host_pattern.contains_scheme = Værtsmønsteret "{ $pattern }" må ikke indeholde et URL-skema. +host_pattern.contains_slash = Værtsmønsteret "{ $pattern }" må ikke indeholde "/". +host_pattern.missing_suffix = Værtsmønsteret "{ $pattern }" skal have et suffiks efter "*.". +host_pattern.empty_label = Værtsmønsteret "{ $pattern }" indeholder en tom etiket. +host_pattern.invalid_chars = Værtsmønsteret "{ $pattern }" indeholder ugyldige tegn. +host_pattern.invalid_label_edge = Etiketter i værtsmønsteret "{ $pattern }" må ikke begynde eller slutte med "-". +host_pattern.label_too_long = Værtsmønsteret "{ $pattern }" indeholder en etiket på over 63 tegn. +host_pattern.too_long = Værtsmønsteret "{ $pattern }" overskrider grænsen på 255 tegn. + +# Netværkspolitik. +network_policy.scheme.empty = Skemaet må ikke være tomt. +network_policy.scheme.invalid = Skemaet "{ $scheme }" indeholder ugyldige tegn. +network_policy.allowlist.empty = Listen over tilladte værter må ikke være tom. +network_policy.scheme.not_allowed = Skemaet "{ $scheme }" er ikke tilladt. +network_policy.missing_host = URL-adressen mangler en vært. +network_policy.host.blocked = Værten "{ $host }" er blokeret af politikken. +network_policy.host.not_allowlisted = Værten "{ $host }" står ikke på listen over tilladte. + +# Konfiguration af standardbiblioteket. +stdlib.config.default_fetch_cache_invalid = Standardstien til fetch-mellemlageret skal være relativ. +stdlib.config.default_which_cache_invalid = Standardkapaciteten for which-mellemlageret skal være positiv. +stdlib.config.workspace_root_absolute = Rodstien for arbejdsområdet skal være absolut. +stdlib.config.fetch_response_limit_positive = Svargrænsen for fetch skal være positiv. +stdlib.config.command_output_limit_positive = Grænsen for opsamlet kommandooutput skal være positiv. +stdlib.config.command_stream_limit_positive = Strømgrænsen for kommandoer skal være positiv. +stdlib.config.which_cache_capacity_positive = Kapaciteten for which-mellemlageret skal være positiv. +stdlib.config.skip_dir_empty = Opslag over oversprungne mapper må ikke være tomme. +stdlib.config.skip_dir_navigation = Opslag over oversprungne mapper må ikke indeholde "..". +stdlib.config.skip_dir_separator = Opslag over oversprungne mapper må ikke indeholde stiadskillere. +stdlib.config.fetch_cache_empty = Stien til fetch-mellemlageret må ikke være tom. +stdlib.config.fetch_cache_not_relative = Stien til fetch-mellemlageret skal være relativ, men gav { $path }. +stdlib.config.fetch_cache_escapes = Stien til fetch-mellemlageret må ikke forlade arbejdsområdet: { $path }. +stdlib.config.open_workspace_root = Den aktuelle mappe kunne ikke åbnes som rod for stdlib-arbejdsområdet. +stdlib.config.resolve_cwd = Den aktuelle mappe kunne ikke bestemmes som rod for stdlib-arbejdsområdet. +stdlib.config.cwd_non_utf8 = Den aktuelle mappe indeholder dele, der ikke er UTF-8: { $path }. + +# Diagnostik for fetch-hjælperen. +stdlib.fetch.url_invalid = Ugyldig URL-adresse "{ $url }": { $details }. +stdlib.fetch.disallowed = URL-adressen "{ $url }" er ikke tilladt: { $details }. +stdlib.fetch.failed = "{ $url }" kunne ikke hentes: { $details }. +stdlib.fetch.cache_read_failed = Opslaget "{ $name }" i mellemlageret kunne ikke læses: { $details }. +stdlib.fetch.cache_open_failed = Opslaget "{ $name }" i mellemlageret kunne ikke åbnes: { $details }. +stdlib.fetch.response_read_failed = Svaret fra "{ $url }" kunne ikke læses: { $details }. +stdlib.fetch.response_buffer_overflow = Bufferoverløb under læsning af "{ $url }". +stdlib.fetch.cache_write_failed = Mellemlageret for "{ $url }" kunne ikke skrives: { $details }. +stdlib.fetch.response_limit_exceeded = Svaret fra "{ $url }" oversteg grænsen på { $limit } byte. +stdlib.fetch.cache_limit_exceeded = Det mellemlagrede svar "{ $name }" oversteg grænsen på { $limit } byte. +stdlib.fetch.io_failed = { $action } mislykkedes for { $path }: { $details }. +stdlib.fetch.action.sync_cache = synkronisering af fetch-mellemlageret +stdlib.fetch.action.create_cache_dir = oprettelse af mappen til fetch-mellemlageret +stdlib.fetch.action.open_cache_dir = åbning af mappen til fetch-mellemlageret +stdlib.fetch.action.stat_cache = opslag på posten i fetch-mellemlageret +stdlib.fetch.action.open_cache_entry = åbning af posten i fetch-mellemlageret + +# Diagnostik for kommandohjælperen. +stdlib.command.location = kommandoen "{ $command }" i skabelonen "{ $template }" +stdlib.command.spawn_failed = { $location } kunne ikke startes: { $details }. +stdlib.command.io_failed = { $location } mislykkedes: { $details }. +stdlib.command.closed_input_early = Inputtet blev lukket, før skrivningen til kommandoen var færdig. +stdlib.command.broken_pipe = Brudt datakanal under kørsel af { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } blev afbrudt af et signal. +stdlib.command.exited_with_status = { $location } afsluttede med status { $status }. +stdlib.command.output_limit_exceeded = { $location } oversteg { $mode }-grænsen på { $limit } byte for { $stream }. +stdlib.command.timeout = { $location } overskred tidsgrænsen på { $seconds } sekunder. +stdlib.command.exit_status_suffix = (afslutningsstatus { $status }) +stdlib.command.signal_suffix = (afbrudt af et signal) +stdlib.command.shell.empty = Skalkommandoen må ikke være tom. +stdlib.command.grep.empty_pattern = Mønsteret til grep må ikke være tomt. +stdlib.command.grep.flags_not_string = Flag til grep skal være strenge. +stdlib.command.quote.invalid = { $arg } kunne ikke sættes i anførselstegn: { $details }. +stdlib.command.quote.line_break = Argumenter med vognretur eller linjeskift kan ikke sættes sikkert i anførselstegn. +stdlib.command.input_undefined = Inputværdien er udefineret. +stdlib.command.tempfile.root_required = Der kræves en rod for arbejdsområdet for at oprette midlertidige kommandofiler. +stdlib.command.tempfile.create_failed = Den midlertidige kommandofil kunne ikke oprettes: { $details }. +stdlib.command.options.invalid_utf8 = Nøglen til et kommandotilvalg skal være gyldig UTF-8. +stdlib.command.option.mode_not_string = Outputtilstanden skal være en streng. +stdlib.command.options.invalid_type = Kommandotilvalg skal være et objekt. +stdlib.command.output.mode_unsupported = Outputtilstanden "{ $mode }" understøttes ikke. +stdlib.command.output.mode.capture = opsamling +stdlib.command.output.mode.streaming = strømning +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Diagnostik for stihjælperen. +stdlib.path.io.failed = { $action } mislykkedes for { $path } ({ $label }). +stdlib.path.io.failed_with_detail = { $action } mislykkedes for { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = { $action } mislykkedes for { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = ikke fundet +stdlib.path.io.permission_denied = adgang nægtet +stdlib.path.io.already_exists = findes allerede +stdlib.path.io.invalid_input = ugyldigt input +stdlib.path.io.invalid_data = ugyldige data +stdlib.path.io.timed_out = tidsgrænsen udløb +stdlib.path.io.interrupted = afbrudt +stdlib.path.io.would_block = ville blokere +stdlib.path.io.write_zero = nul byte skrevet +stdlib.path.io.unexpected_eof = uventet filslutning +stdlib.path.io.broken_pipe = brudt datakanal +stdlib.path.io.connection_refused = forbindelse afvist +stdlib.path.io.connection_reset = forbindelse nulstillet +stdlib.path.io.connection_aborted = forbindelse afbrudt +stdlib.path.io.not_connected = ikke forbundet +stdlib.path.io.addr_in_use = adressen er i brug +stdlib.path.io.addr_not_available = adressen er ikke tilgængelig +stdlib.path.io.out_of_memory = ikke mere hukommelse +stdlib.path.io.unsupported = understøttes ikke +stdlib.path.io.file_too_large = filen er for stor +stdlib.path.io.resource_busy = ressourcen er optaget +stdlib.path.io.executable_busy = programfilen er optaget +stdlib.path.io.deadlock = baglås +stdlib.path.io.crosses_devices = krydser enheder +stdlib.path.io.too_many_links = for mange kæder +stdlib.path.io.invalid_filename = ugyldigt filnavn +stdlib.path.io.arg_list_too_long = argumentlisten er for lang +stdlib.path.io.stale_handle = forældet netværksfilreference +stdlib.path.io.storage_full = lageret er fuldt +stdlib.path.io.not_seekable = kan ikke søges i +stdlib.path.io.network_down = netværket er nede +stdlib.path.io.network_unreachable = netværket kan ikke nås +stdlib.path.io.host_unreachable = værten kan ikke nås +stdlib.path.io.other = I/O-fejl +stdlib.path.action.canonicalize = kanonisering +stdlib.path.action.open_directory = åbning af mappe +stdlib.path.action.stat = opslag +stdlib.path.action.read = læsning +stdlib.path.action.open_file = åbning af fil +stdlib.path.with_suffix.empty_separator = with_suffix kræver en adskiller, der ikke er tom. +stdlib.path.relative_to.mismatch = { $path } er ikke relativ til { $root }. +stdlib.path.expanduser.unsupported = Brugerspecifik udvidelse af ~ understøttes ikke. +stdlib.path.expanduser.no_home = ~ kan ikke udvides: der er ingen miljøvariabler for hjemmemappen. +stdlib.path.contents.unsupported_encoding = Tegnkodningen "{ $encoding }" understøttes ikke. +stdlib.path.hash.unsupported_algorithm = Hash-algoritmen "{ $algorithm }" understøttes ikke. +stdlib.path.hash.unsupported_algorithm_legacy = Hash-algoritmen "{ $algorithm }" understøttes ikke (slå funktionen "{ $feature }" til). + +# Diagnostik for samlingshjælpere. +stdlib.collections.flatten.expected_sequence = flatten forventede elementer fra en følge, men fandt { $kind }. +stdlib.collections.group_by.empty_attribute = group_by kræver en attribut, der ikke er tom. +stdlib.collections.group_by.unresolved = group_by kunne ikke slå "{ $attr }" op på et element af typen { $kind }. + +# Diagnostik for tidshjælpere. +stdlib.time.offset.invalid = Forskydningen for now "{ $offset }" er ugyldig: forventede "+HH:MM[:SS]" eller "Z". +stdlib.time.timedelta.overflow = Overløb i timedelta ved tilføjelse af { $component }. +stdlib.time.label.weeks = uger +stdlib.time.label.days = dage +stdlib.time.label.hours = timer +stdlib.time.label.minutes = minutter +stdlib.time.label.seconds = sekunder +stdlib.time.label.milliseconds = millisekunder +stdlib.time.label.microseconds = mikrosekunder +stdlib.time.label.nanoseconds = nanosekunder + +# Diagnostik for which-hjælperen. +stdlib.which.not_found = [netsuke::jinja::which::not_found] kommandoen "{ $command }" blev ikke fundet efter gennemgang af { $count } PATH-opslag. Uddrag: { $preview } +stdlib.which.not_found.hint.cwd_auto = Tomme dele af PATH ignoreres; brug cwd_mode="auto" for at medtage arbejdsmappen. +stdlib.which.not_found.hint.cwd_always = Sæt cwd_mode="always" for at medtage den aktuelle mappe. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] kommandoen "{ $command }" i "{ $path }" mangler eller kan ikke køres. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = PATH-opslag nr. { $index } indeholder tegn, der ikke er UTF-8; Netsuke kræver UTF-8-stier. +stdlib.which.command.empty = which kræver en streng, der ikke er tom. +stdlib.which.cwd_mode.invalid = cwd_mode skal være "auto", "always" eller "never", men gav "{ $mode }". +stdlib.which.cwd.resolve_failed = Den aktuelle mappe kunne ikke bestemmes: { $details }. +stdlib.which.cwd.non_utf8 = Den aktuelle mappe indeholder dele, der ikke er UTF-8. +stdlib.which.canonicalize_failed = "{ $path }" kunne ikke kanoniseres: { $details }. +stdlib.which.is_executable = Det kunne ikke afgøres, om "{ $path }" kan køres: { $details }. +stdlib.which.canonicalize_non_utf8 = Den kanoniske sti indeholder dele, der ikke er UTF-8. +stdlib.which.workspace_non_utf8 = Stien til arbejdsområdet indeholder dele, der ikke er UTF-8, under opslag af kommandoen "{ $command }": { $path }. +stdlib.which.walkdir_error = Fejl under gennemgang af arbejdsområdet ved opslag af kommandoen: { $details }. + +# Registrering af standardbiblioteket. +stdlib.register.open_dir = Den aktuelle mappe kunne ikke åbnes til registrering af stdlib. +stdlib.register.resolve_dir = Den aktuelle mappe kunne ikke bestemmes til registrering af stdlib. +stdlib.register.dir_non_utf8 = Den aktuelle mappe indeholder dele, der ikke er UTF-8: { $path }. + +# Statusrapportering i tilgængelig outputtilstand. +status.state.pending = afventer +status.state.running = i gang +status.state.done = færdig +status.state.failed = mislykkedes +status.stage.label = Trin { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Opgave { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Læser manifestfilen +status.stage.initial_yaml_parsing = Indlæser YAML-dokumentet +status.stage.template_expansion = Udfolder skabelondirektiver +status.stage.final_rendering = Deserialiserer og gengiver manifestets værdier +status.stage.ir_generation_validation = Bygger og validerer afhængighedsgrafen +status.stage.ninja_synthesis = Danner Ninja-byggeplanen +status.stage.ninja_synthesis_execute = Danner Ninja-planen og kører { $tool } +status.stage.graph_rendering = Gengiver grafartefaktet +status.stage.graph_rendering_with_tool = Gengiver { $tool } +status.complete = { $tool } fuldført. +status.timing.summary_header = Tidsopsummering pr. trin: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Samlet tid for kæden: { $duration } +status.tool.build = Bygning +status.tool.clean = Oprydning +status.tool.graph = Graf +status.tool.graph_html = Graf (HTML) +status.tool.generate = Generering + +# Tekster til HTML-gengivelsen af grafen. +graph.html.title = Netsuke-byggegraf +graph.html.heading = Netsuke-byggegraf +graph.html.description = Byggegraf gengivet af Netsuke +graph.html.outline.summary = Mål og afhængigheder (tekstoversigt) +graph.html.outline.no_inputs = Ingen input +graph.html.noscript.notice = JavaScript er slået fra. Tekstoversigten ovenfor er hele grafen; DOT-kildeteksten følger nedenfor. + +# Semantiske præfikser til tilgængeligt output. +semantic.prefix.error = Fejl: +semantic.prefix.warning = Advarsel: +semantic.prefix.success = Succes: +semantic.prefix.info = Info: +semantic.prefix.timing = Tid: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Eksempler på flertalsformer til oversættere. +# Dansk bruger CLDR-kategorierne `one` og `other` som kildesproget. +example.files_processed = { $count -> + [one] Behandlede { $count } fil. + *[other] Behandlede { $count } filer. +} + +example.errors_found = { $count -> + [0] Ingen fejl fundet. + [one] { $count } fejl fundet. + *[other] { $count } fejl fundet. +} diff --git a/locales/de/messages.ftl b/locales/de/messages.ftl new file mode 100644 index 000000000..454e45318 --- /dev/null +++ b/locales/de/messages.ftl @@ -0,0 +1,397 @@ +# Lokalisierungsressourcen für die Netsuke-CLI. + +cli.about = Netsuke übersetzt YAML- + Jinja-Manifeste in Ninja-Build-Pläne. +cli.long_about = Netsuke wandelt YAML- + Jinja-Manifeste in reproduzierbare Ninja-Graphen um und führt Ninja mit sicheren Voreinstellungen aus. +cli.usage = { $usage } + +# Hilfetext für globale Optionen. +cli.flag.file.help = Pfad zur zu verwendenden Netsuke-Manifestdatei. +cli.flag.directory.help = So ausführen, als wäre in diesem Verzeichnis gestartet worden. +cli.flag.config.help = Pfad zu einer Konfigurationsdatei; überspringt die automatische Suche. +cli.flag.jobs.help = Anzahl der parallelen Build-Jobs festlegen. +cli.flag.verbose.help = Ausführliche Diagnoseprotokolle und Zeitübersichten nach Abschluss aktivieren. +cli.flag.locale.help = Sprachkennung für CLI-Texte (zum Beispiel: en-US, de). +cli.flag.fetch_allow_scheme.help = Zusätzliche URL-Schemata, die der fetch-Helfer verwenden darf. +cli.flag.fetch_allow_host.help = Hostnamen, die bei aktivierter Standardsperre zugelassen sind. +cli.flag.fetch_block_host.help = Hostnamen, die immer blockiert werden, auch wenn sie anderweitig erlaubt sind. +cli.flag.fetch_default_deny.help = Alle Hosts standardmäßig sperren; nur die deklarierte Positivliste zulassen. +cli.flag.json.help = Maschinenlesbare JSON-Ausgabe erzeugen. +cli.flag.no_input.help = Niemals interaktive Eingaben lesen. +cli.flag.color.help = Richtlinie für Farbausgabe (auto, always, never). +cli.flag.emoji.help = Emoji-Richtlinie (auto, always, never). +cli.flag.progress.help = Richtlinie für Fortschrittsanzeige (auto, always, never). +cli.flag.accessibility.help = Richtlinie für barrierefreie Ausgabe (auto, on, off). +cli.flag.default_targets.help = Standard-Build-Ziele, wenn keine angegeben werden. + +# Beschreibungen der Unterbefehle. +cli.subcommand.build.about = Im Manifest definierte Ziele bauen (Standard). +cli.subcommand.build.long_about = Die angeforderten Ziele bauen; ohne Angabe werden die Standardziele des Manifests verwendet. +cli.subcommand.clean.about = Build-Artefakte über Ninja entfernen. +cli.subcommand.clean.long_about = Eine temporäre Ninja-Datei erzeugen und anschließend `ninja -t clean` ausführen. +cli.subcommand.graph.about = Den Build-Abhängigkeitsgraphen ausgeben. Standardformat ist DOT. +cli.subcommand.graph.long_about = Das eingelesene Netsuke-Manifest in einen kanonischen Build-Graphen überführen und als Graphviz-DOT ausgeben oder mit `--html` als eigenständige HTML-Seite. Mit `--output ` in eine Datei schreiben; `-` schreibt nach stdout. +cli.subcommand.generate.about = Das Ninja-Manifest erzeugen, ohne Ninja auszuführen. +cli.subcommand.generate.long_about = Das erzeugte Ninja-Manifest nach stdout schreiben oder in eine mit `--output` gewählte Datei. + +# Hilfetext für Optionen des Unterbefehls build. +cli.subcommand.build.flag.targets.help = Zu bauende Ziele (ohne Angabe gelten die Standardziele des Manifests). + +# Hilfetext für Optionen des Unterbefehls graph. +cli.subcommand.graph.flag.html.help = Den Graphen statt als DOT als eigenständige HTML-Seite rendern. +cli.subcommand.graph.flag.output.help = Das Graph-Artefakt in DATEI schreiben; `-` für stdout verwenden. + +# Hilfetext für Optionen des Unterbefehls generate. +cli.subcommand.generate.flag.output.help = Das erzeugte Ninja-Manifest statt nach stdout in DATEI schreiben. + +# Validierungsfehler der CLI. +cli.validation.jobs.invalid_number = { $value } ist keine gültige Zahl. +cli.validation.jobs.out_of_range = Die Job-Anzahl muss zwischen { $min } und { $max } liegen. +cli.validation.scheme.empty = Das Schema darf nicht leer sein. +cli.validation.scheme.invalid_start = Das Schema „{ $scheme }“ muss mit einem ASCII-Buchstaben beginnen. +cli.validation.scheme.invalid = Ungültiges Schema „{ $scheme }“. +cli.validation.locale.empty = Die Sprachkennung darf nicht leer sein. +cli.validation.locale.invalid = Ungültige Sprachkennung „{ $locale }“. +cli.validation.color.invalid = Ungültige Farbrichtlinie „{ $value }“. Gültige Optionen: auto, always, never. +cli.validation.emoji.invalid = Ungültige Emoji-Richtlinie „{ $value }“. Gültige Optionen: auto, always, never. +cli.validation.progress.invalid = Ungültige Fortschrittsrichtlinie „{ $value }“. Gültige Optionen: auto, always, never. +cli.validation.accessibility.invalid = Ungültige Barrierefreiheitsrichtlinie „{ $value }“. Gültige Optionen: auto, on, off. +cli.validation.config.expected_object = Die eingelesenen CLI-Werte sollten als Objekt serialisiert werden, erhalten wurde { $value }. + +# Fehlermeldungen von Clap. +clap-error-missing-argument = Erforderliches Argument fehlt: { $argument } +clap-error-missing-subcommand = Unterbefehl fehlt. Verfügbare Optionen: { $valid_subcommands } +clap-error-unknown-argument = Unbekanntes Argument: { $argument } +clap-error-invalid-value = Ungültiger Wert für { $argument }: { $value } +clap-error-invalid-subcommand = Unbekannter Unterbefehl: { $subcommand } +# Hinweis: value-validation ist bewusst anders formuliert als invalid-value, um +# Fehler eigener Validierer (ErrorKind::ValueValidation) von Typkonflikten +# (ErrorKind::InvalidValue) zu unterscheiden. +clap-error-value-validation = Validierung fehlgeschlagen für { $argument }: { $value } + +# Fehler und Kontexte des Runners. +runner.manifest.not_found = Manifest „{ $manifest_name }“ wurde in { $directory } nicht gefunden. +runner.manifest.not_found.help = Stellen Sie sicher, dass das Manifest existiert, oder geben Sie `--file` mit dem richtigen Pfad an. +runner.manifest.path_missing_name = Der Manifestpfad „{ $path }“ enthält keinen Dateinamen. +runner.manifest.path_utf8 = Der Manifestpfad „{ $path }“ ist kein gültiges UTF-8. +runner.manifest.directory_utf8 = Der Pfad des Manifestverzeichnisses „{ $path }“ ist kein gültiges UTF-8. +runner.manifest.directory_label = Verzeichnis `{ $directory }` +runner.manifest.current_directory_label = das aktuelle Verzeichnis +runner.context.network_policy = Die Netzwerkrichtlinie konnte nicht erstellt werden. +runner.context.load_manifest = Das Manifest unter { $path } konnte nicht geladen werden. +runner.context.serialise_manifest = Das Manifest konnte nicht serialisiert werden. +runner.context.build_graph = Aus dem Manifest konnte kein Graph erstellt werden. +runner.context.generate_ninja = Das Ninja-Manifest konnte nicht erzeugt werden. +runner.context.render_graph = Das Graph-Artefakt konnte nicht gerendert werden. + +runner.io.create_temp_file = Die temporäre Ninja-Datei konnte nicht erstellt werden. +runner.io.write_temp_ninja = Die temporäre Ninja-Datei konnte nicht geschrieben werden. +runner.io.flush_temp_ninja = Die temporäre Ninja-Datei konnte nicht geleert werden. +runner.io.sync_temp_ninja = Die temporäre Ninja-Datei konnte nicht synchronisiert werden. +runner.io.create_parent_dir = Das übergeordnete Verzeichnis { $path } konnte nicht erstellt werden. +runner.io.create_ninja_file = Die Ninja-Datei unter { $path } konnte nicht erstellt werden. +runner.io.write_ninja_file = Die Ninja-Datei unter { $path } konnte nicht geschrieben werden. +runner.io.flush_ninja_file = Die Ninja-Datei unter { $path } konnte nicht geleert werden. +runner.io.sync_ninja_file = Die Ninja-Datei unter { $path } konnte nicht synchronisiert werden. +runner.io.open_ambient_dir = Das umgebende Verzeichnis konnte nicht geöffnet werden. +runner.io.no_existing_ancestor = Für { $path } existiert kein übergeordnetes Verzeichnis. +runner.io.derive_relative_path = Der relative Ninja-Pfad konnte nicht abgeleitet werden. +runner.io.non_utf8_path = Pfade ohne gültiges UTF-8 werden nicht unterstützt (Pfad: { $path }). +runner.io.write_stdout = Das Ninja-Manifest konnte nicht nach stdout geschrieben werden. +runner.io.flush_stdout = stdout konnte nicht geleert werden. + +# Manifest-Diagnosen. +manifest.parse = Das Parsen des Manifests ist fehlgeschlagen. +manifest.structure_error = Strukturfehler im Manifest bei { $name }: { $details } +manifest.yaml.parse = YAML-Fehler in Zeile { $line }, Spalte { $column }: { $details } +manifest.yaml.label = ungültiges YAML +manifest.yaml.hint.tabs = YAML erlaubt keine Tabulatoren; verwenden Sie Leerzeichen zur Einrückung. +manifest.yaml.hint.list_item = YAML-Listeneinträge müssen mit „-“ beginnen und korrekt eingerückt sein. +manifest.yaml.hint.expected_colon = Das sieht nach einem Mapping-Eintrag aus; nach dem Schlüssel fehlt ein „:“. +manifest.yaml.hint.mapping_values = YAML-Mappings benötigen nach „:“ einen Wert (oder einen eingerückten Block). +manifest.yaml.hint.invalid_token = Das YAML-Token ist ungültig oder unerwartet. +manifest.yaml.hint.escape = Maskieren Sie Backslashes oder entfernen Sie ungültige Escape-Sequenzen. +manifest.env.missing = Die erforderliche Umgebungsvariable „{ $name }“ ist nicht gesetzt. +manifest.env.invalid_utf8 = Die Umgebungsvariable „{ $name }“ enthält ungültiges UTF-8. +manifest.vars.not_object = `vars` im Manifest muss eine Zuordnung bzw. ein Objekt sein. +manifest.read_failed = Das Manifest unter { $path } konnte nicht gelesen werden. +manifest.resolve_workspace_root = Das Wurzelverzeichnis des Arbeitsbereichs konnte nicht ermittelt werden. +manifest.workspace_non_utf8 = Der Wurzelpfad des Arbeitsbereichs „{ $path }“ ist kein gültiges UTF-8. +manifest.path_non_utf8 = Der Pfad des Manifests „{ $manifest }“ ist kein gültiges UTF-8: { $path }. +manifest.path_missing_name = Der Manifestpfad „{ $path }“ enthält keinen Dateinamen. +manifest.open_workspace_failed = Der Arbeitsbereich { $workspace } konnte für das Manifest { $manifest } nicht geöffnet werden. +manifest.foreach.not_iterable = Der Ausdruck `foreach` ist nicht iterierbar. +manifest.foreach.serialise_item = Das foreach-Element konnte nicht serialisiert werden. +manifest.when.empty = Der Ausdruck `when` darf nicht leer sein. +manifest.when.eval_error = Der Ausdruck `when` „{ $expr }“ konnte nicht ausgewertet werden. +manifest.when.template_error = Die Vorlage `when` „{ $expr }“ konnte nicht gerendert werden. +manifest.target.vars_not_object = `vars` des Ziels muss ein Objekt sein, erhalten wurde { $value }. +manifest.vars.entry_not_object = Ein `vars`-Eintrag des Manifests muss ein Objekt sein. +manifest.field_not_string = Das Feld „{ $field }“ muss eine Zeichenkette sein. +manifest.expression.parse_error = Der Ausdruck { $name } konnte nicht geparst werden. +manifest.expression.eval_error = Der Ausdruck { $name } konnte nicht ausgewertet werden. + +# Diagnosen zu Manifest-Makros. +manifest.macro.signature_missing_identifier = Der Makro-Signatur fehlt ein Bezeichner. +manifest.macro.signature_missing_params = Der Makro-Signatur fehlen Parameter. +manifest.macro.compile_failed = Das Makro { $name } konnte nicht kompiliert werden. +manifest.macro.sequence_invalid = Makros müssen als Zuordnung von Namen zu Vorlagen definiert werden. +manifest.macro.register_failed = Die Manifest-Makros konnten nicht registriert werden. +manifest.macro.not_initialised = Die Makro-Umgebung ist nicht initialisiert. +manifest.macro.caller_invalid = Der Makro-Aufrufer muss eine Zeichenkette sein. +manifest.macro.template_load_failed = Die Makro-Vorlage konnte nicht geladen werden. +manifest.macro.init_failed = Die Makro-Umgebung konnte nicht initialisiert werden. +manifest.macro.missing = Das Makro { $name } fehlt. + +# Glob-Fehler im Manifest. +manifest.glob.unmatched_brace = Ungültiges Glob-Muster „{ $pattern }“: „{ $character }“ ohne Gegenstück an Position { $position }. +manifest.glob.invalid_pattern = Ungültiges Glob-Muster „{ $pattern }“: { $detail }. +manifest.glob.unknown_pattern_error = unbekannter Musterfehler. +manifest.glob.io_failed = Glob für „{ $pattern }“ fehlgeschlagen: { $detail }. +manifest.glob.unknown_io_error = unbekannter E/A-Fehler. + +# Fehler der Zwischendarstellung. +ir.rule_not_found = Die vom Ziel „{ $target }“ referenzierte Regel „{ $rule }“ wurde nicht gefunden. +ir.multiple_rules = Das Ziel „{ $target }“ muss genau eine Regel referenzieren, erhalten wurde { $rules }. +ir.empty_rule = Das Ziel „{ $target }“ muss eine Regel referenzieren. +ir.duplicate_outputs = Doppelte Ausgaben erkannt: { $outputs }. +ir.circular_dependency = Zyklische Abhängigkeit erkannt: { $cycle }. +ir.action_serialisation = Die Aktion konnte nicht serialisiert werden: { $details }. +ir.invalid_command = Ungültige Befehlsinterpolation: { $snippet }. + +# Fehler bei der Ninja-Erzeugung. +ninja_gen.missing_action = Die von einer Build-Kante referenzierte Aktion „{ $id }“ fehlt. +ninja_gen.format = Die Ausgabe des Ninja-Manifests konnte nicht formatiert werden. + +# Validierung von Host-Mustern. +host_pattern.empty = Das Host-Muster darf nicht leer sein. +host_pattern.contains_scheme = Das Host-Muster „{ $pattern }“ darf kein URL-Schema enthalten. +host_pattern.contains_slash = Das Host-Muster „{ $pattern }“ darf kein „/“ enthalten. +host_pattern.missing_suffix = Das Host-Muster „{ $pattern }“ muss nach „*.“ ein Suffix enthalten. +host_pattern.empty_label = Das Host-Muster „{ $pattern }“ enthält ein leeres Label. +host_pattern.invalid_chars = Das Host-Muster „{ $pattern }“ enthält ungültige Zeichen. +host_pattern.invalid_label_edge = Labels des Host-Musters „{ $pattern }“ dürfen nicht mit „-“ beginnen oder enden. +host_pattern.label_too_long = Das Host-Muster „{ $pattern }“ enthält ein Label mit mehr als 63 Zeichen. +host_pattern.too_long = Das Host-Muster „{ $pattern }“ überschreitet die Grenze von 255 Zeichen. + +# Netzwerkrichtlinie. +network_policy.scheme.empty = Das Schema darf nicht leer sein. +network_policy.scheme.invalid = Das Schema „{ $scheme }“ enthält ungültige Zeichen. +network_policy.allowlist.empty = Die Host-Positivliste darf nicht leer sein. +network_policy.scheme.not_allowed = Das Schema „{ $scheme }“ ist nicht zugelassen. +network_policy.missing_host = Der URL fehlt ein Host. +network_policy.host.blocked = Der Host „{ $host }“ ist durch die Richtlinie blockiert. +network_policy.host.not_allowlisted = Der Host „{ $host }“ steht nicht auf der Positivliste. + +# Konfiguration der Standardbibliothek. +stdlib.config.default_fetch_cache_invalid = Der voreingestellte Pfad des fetch-Caches muss relativ sein. +stdlib.config.default_which_cache_invalid = Die voreingestellte Kapazität des which-Caches muss positiv sein. +stdlib.config.workspace_root_absolute = Der Wurzelpfad des Arbeitsbereichs muss absolut sein. +stdlib.config.fetch_response_limit_positive = Das Antwortlimit von fetch muss positiv sein. +stdlib.config.command_output_limit_positive = Das Limit für erfasste Befehlsausgaben muss positiv sein. +stdlib.config.command_stream_limit_positive = Das Stream-Limit für Befehle muss positiv sein. +stdlib.config.which_cache_capacity_positive = Die Kapazität des which-Caches muss positiv sein. +stdlib.config.skip_dir_empty = Einträge zu übersprungenen Verzeichnissen dürfen nicht leer sein. +stdlib.config.skip_dir_navigation = Einträge zu übersprungenen Verzeichnissen dürfen kein „..“ enthalten. +stdlib.config.skip_dir_separator = Einträge zu übersprungenen Verzeichnissen dürfen keine Pfadtrenner enthalten. +stdlib.config.fetch_cache_empty = Der Pfad des fetch-Caches darf nicht leer sein. +stdlib.config.fetch_cache_not_relative = Der Pfad des fetch-Caches muss relativ sein, erhalten wurde { $path }. +stdlib.config.fetch_cache_escapes = Der Pfad des fetch-Caches darf den Arbeitsbereich nicht verlassen: { $path }. +stdlib.config.open_workspace_root = Das aktuelle Verzeichnis konnte nicht als Wurzel des stdlib-Arbeitsbereichs geöffnet werden. +stdlib.config.resolve_cwd = Das aktuelle Verzeichnis konnte nicht als Wurzel des stdlib-Arbeitsbereichs ermittelt werden. +stdlib.config.cwd_non_utf8 = Das aktuelle Verzeichnis enthält Komponenten ohne gültiges UTF-8: { $path }. + +# Diagnosen des fetch-Helfers. +stdlib.fetch.url_invalid = Ungültige URL „{ $url }“: { $details }. +stdlib.fetch.disallowed = Die URL „{ $url }“ ist nicht zugelassen: { $details }. +stdlib.fetch.failed = „{ $url }“ konnte nicht abgerufen werden: { $details }. +stdlib.fetch.cache_read_failed = Der Cache-Eintrag „{ $name }“ konnte nicht gelesen werden: { $details }. +stdlib.fetch.cache_open_failed = Der Cache-Eintrag „{ $name }“ konnte nicht geöffnet werden: { $details }. +stdlib.fetch.response_read_failed = Die Antwort von „{ $url }“ konnte nicht gelesen werden: { $details }. +stdlib.fetch.response_buffer_overflow = Pufferüberlauf beim Lesen von „{ $url }“. +stdlib.fetch.cache_write_failed = Der Cache für „{ $url }“ konnte nicht geschrieben werden: { $details }. +stdlib.fetch.response_limit_exceeded = Die Antwort von „{ $url }“ überschritt das Limit von { $limit } Byte. +stdlib.fetch.cache_limit_exceeded = Die zwischengespeicherte Antwort „{ $name }“ überschritt das Limit von { $limit } Byte. +stdlib.fetch.io_failed = { $action } für { $path } fehlgeschlagen: { $details }. +stdlib.fetch.action.sync_cache = Synchronisieren des fetch-Caches +stdlib.fetch.action.create_cache_dir = Erstellen des fetch-Cache-Verzeichnisses +stdlib.fetch.action.open_cache_dir = Öffnen des fetch-Cache-Verzeichnisses +stdlib.fetch.action.stat_cache = Abfragen des fetch-Cache-Eintrags +stdlib.fetch.action.open_cache_entry = Öffnen des fetch-Cache-Eintrags + +# Diagnosen des Befehlshelfers. +stdlib.command.location = Befehl „{ $command }“ in der Vorlage „{ $template }“ +stdlib.command.spawn_failed = { $location } konnte nicht gestartet werden: { $details }. +stdlib.command.io_failed = { $location } fehlgeschlagen: { $details }. +stdlib.command.closed_input_early = Die Eingabe wurde geschlossen, bevor das Schreiben an den Befehl abgeschlossen war. +stdlib.command.broken_pipe = Unterbrochene Pipe beim Ausführen von { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } wurde durch ein Signal beendet. +stdlib.command.exited_with_status = { $location } wurde mit Status { $status } beendet. +stdlib.command.output_limit_exceeded = { $location } überschritt das { $mode }-Limit von { $limit } Byte für { $stream }. +stdlib.command.timeout = { $location } überschritt die Zeitgrenze von { $seconds } Sekunden. +stdlib.command.exit_status_suffix = (Exit-Status { $status }) +stdlib.command.signal_suffix = (durch Signal beendet) +stdlib.command.shell.empty = Der Shell-Befehl darf nicht leer sein. +stdlib.command.grep.empty_pattern = Das grep-Muster darf nicht leer sein. +stdlib.command.grep.flags_not_string = grep-Flags müssen Zeichenketten sein. +stdlib.command.quote.invalid = { $arg } konnte nicht in Anführungszeichen gesetzt werden: { $details }. +stdlib.command.quote.line_break = Argumente mit Wagenrücklauf oder Zeilenumbruch lassen sich nicht sicher in Anführungszeichen setzen. +stdlib.command.input_undefined = Der Eingabewert ist nicht definiert. +stdlib.command.tempfile.root_required = Zum Anlegen temporärer Befehlsdateien wird die Wurzel des Arbeitsbereichs benötigt. +stdlib.command.tempfile.create_failed = Die temporäre Befehlsdatei konnte nicht erstellt werden: { $details }. +stdlib.command.options.invalid_utf8 = Der Schlüssel einer Befehlsoption muss gültiges UTF-8 sein. +stdlib.command.option.mode_not_string = Der Ausgabemodus muss eine Zeichenkette sein. +stdlib.command.options.invalid_type = Befehlsoptionen müssen ein Objekt sein. +stdlib.command.output.mode_unsupported = Nicht unterstützter Ausgabemodus „{ $mode }“. +stdlib.command.output.mode.capture = Erfassung +stdlib.command.output.mode.streaming = Streaming +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Diagnosen des Pfadhelfers. +stdlib.path.io.failed = { $action } für { $path } fehlgeschlagen ({ $label }). +stdlib.path.io.failed_with_detail = { $action } für { $path } fehlgeschlagen: { $detail }. +stdlib.path.io.failed_with_label_and_detail = { $action } für { $path } fehlgeschlagen ({ $label }): { $detail }. +stdlib.path.io.not_found = nicht gefunden +stdlib.path.io.permission_denied = Zugriff verweigert +stdlib.path.io.already_exists = existiert bereits +stdlib.path.io.invalid_input = ungültige Eingabe +stdlib.path.io.invalid_data = ungültige Daten +stdlib.path.io.timed_out = Zeitüberschreitung +stdlib.path.io.interrupted = unterbrochen +stdlib.path.io.would_block = würde blockieren +stdlib.path.io.write_zero = null Bytes geschrieben +stdlib.path.io.unexpected_eof = unerwartetes Dateiende +stdlib.path.io.broken_pipe = unterbrochene Pipe +stdlib.path.io.connection_refused = Verbindung abgelehnt +stdlib.path.io.connection_reset = Verbindung zurückgesetzt +stdlib.path.io.connection_aborted = Verbindung abgebrochen +stdlib.path.io.not_connected = nicht verbunden +stdlib.path.io.addr_in_use = Adresse bereits belegt +stdlib.path.io.addr_not_available = Adresse nicht verfügbar +stdlib.path.io.out_of_memory = kein Speicher mehr +stdlib.path.io.unsupported = nicht unterstützt +stdlib.path.io.file_too_large = Datei zu groß +stdlib.path.io.resource_busy = Ressource belegt +stdlib.path.io.executable_busy = ausführbare Datei belegt +stdlib.path.io.deadlock = Verklemmung +stdlib.path.io.crosses_devices = überschreitet Gerätegrenzen +stdlib.path.io.too_many_links = zu viele Verknüpfungen +stdlib.path.io.invalid_filename = ungültiger Dateiname +stdlib.path.io.arg_list_too_long = Argumentliste zu lang +stdlib.path.io.stale_handle = veralteter Netzwerk-Dateizeiger +stdlib.path.io.storage_full = Speicher voll +stdlib.path.io.not_seekable = nicht positionierbar +stdlib.path.io.network_down = Netzwerk ausgefallen +stdlib.path.io.network_unreachable = Netzwerk nicht erreichbar +stdlib.path.io.host_unreachable = Host nicht erreichbar +stdlib.path.io.other = E/A-Fehler +stdlib.path.action.canonicalize = Kanonisieren +stdlib.path.action.open_directory = Öffnen des Verzeichnisses +stdlib.path.action.stat = Abfragen +stdlib.path.action.read = Lesen +stdlib.path.action.open_file = Öffnen der Datei +stdlib.path.with_suffix.empty_separator = with_suffix benötigt ein nicht leeres Trennzeichen. +stdlib.path.relative_to.mismatch = { $path } ist nicht relativ zu { $root }. +stdlib.path.expanduser.unsupported = Die benutzerspezifische Erweiterung von ~ wird nicht unterstützt. +stdlib.path.expanduser.no_home = ~ kann nicht erweitert werden: Es sind keine Umgebungsvariablen für das Heimatverzeichnis gesetzt. +stdlib.path.contents.unsupported_encoding = Nicht unterstützte Kodierung „{ $encoding }“. +stdlib.path.hash.unsupported_algorithm = Nicht unterstützter Hash-Algorithmus „{ $algorithm }“. +stdlib.path.hash.unsupported_algorithm_legacy = Nicht unterstützter Hash-Algorithmus „{ $algorithm }“ (aktivieren Sie das Feature „{ $feature }“). + +# Diagnosen der Sammlungshelfer. +stdlib.collections.flatten.expected_sequence = flatten erwartete Sequenzelemente, fand aber { $kind }. +stdlib.collections.group_by.empty_attribute = group_by benötigt ein nicht leeres Attribut. +stdlib.collections.group_by.unresolved = group_by konnte „{ $attr }“ an einem Element vom Typ { $kind } nicht auflösen. + +# Diagnosen der Zeithelfer. +stdlib.time.offset.invalid = Der now-Offset „{ $offset }“ ist ungültig: erwartet wurde „+HH:MM[:SS]“ oder „Z“. +stdlib.time.timedelta.overflow = Überlauf in timedelta beim Addieren von { $component }. +stdlib.time.label.weeks = Wochen +stdlib.time.label.days = Tage +stdlib.time.label.hours = Stunden +stdlib.time.label.minutes = Minuten +stdlib.time.label.seconds = Sekunden +stdlib.time.label.milliseconds = Millisekunden +stdlib.time.label.microseconds = Mikrosekunden +stdlib.time.label.nanoseconds = Nanosekunden + +# Diagnosen des which-Helfers. +stdlib.which.not_found = [netsuke::jinja::which::not_found] Befehl „{ $command }“ nach Prüfung von { $count } PATH-Einträgen nicht gefunden. Vorschau: { $preview } +stdlib.which.not_found.hint.cwd_auto = Leere PATH-Segmente werden ignoriert; verwenden Sie cwd_mode="auto", um das Arbeitsverzeichnis einzubeziehen. +stdlib.which.not_found.hint.cwd_always = Setzen Sie cwd_mode="always", um das aktuelle Verzeichnis einzubeziehen. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] Der Befehl „{ $command }“ unter „{ $path }“ fehlt oder ist nicht ausführbar. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = Der PATH-Eintrag Nr. { $index } enthält Zeichen ohne gültiges UTF-8; Netsuke benötigt UTF-8-Pfade. +stdlib.which.command.empty = which benötigt eine nicht leere Zeichenkette. +stdlib.which.cwd_mode.invalid = cwd_mode muss „auto“, „always“ oder „never“ sein, erhalten wurde „{ $mode }“. +stdlib.which.cwd.resolve_failed = Das aktuelle Verzeichnis konnte nicht ermittelt werden: { $details }. +stdlib.which.cwd.non_utf8 = Das aktuelle Verzeichnis enthält Komponenten ohne gültiges UTF-8. +stdlib.which.canonicalize_failed = „{ $path }“ konnte nicht kanonisiert werden: { $details }. +stdlib.which.is_executable = Es konnte nicht geprüft werden, ob „{ $path }“ ausführbar ist: { $details }. +stdlib.which.canonicalize_non_utf8 = Der kanonische Pfad enthält Komponenten ohne gültiges UTF-8. +stdlib.which.workspace_non_utf8 = Der Arbeitsbereichspfad enthält beim Auflösen des Befehls „{ $command }“ Komponenten ohne gültiges UTF-8: { $path }. +stdlib.which.walkdir_error = Fehler beim Durchlaufen des Arbeitsbereichs während der Befehlsauflösung: { $details }. + +# Registrierung der Standardbibliothek. +stdlib.register.open_dir = Das aktuelle Verzeichnis konnte für die stdlib-Registrierung nicht geöffnet werden. +stdlib.register.resolve_dir = Das aktuelle Verzeichnis konnte für die stdlib-Registrierung nicht ermittelt werden. +stdlib.register.dir_non_utf8 = Das aktuelle Verzeichnis enthält Komponenten ohne gültiges UTF-8: { $path }. + +# Statusmeldungen für die barrierefreie Ausgabe. +status.state.pending = ausstehend +status.state.running = läuft +status.state.done = fertig +status.state.failed = fehlgeschlagen +status.stage.label = Phase { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Aufgabe { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Manifestdatei wird gelesen +status.stage.initial_yaml_parsing = YAML-Dokument wird geparst +status.stage.template_expansion = Vorlagendirektiven werden expandiert +status.stage.final_rendering = Manifestwerte werden deserialisiert und gerendert +status.stage.ir_generation_validation = Abhängigkeitsgraph wird erstellt und geprüft +status.stage.ninja_synthesis = Ninja-Build-Plan wird erzeugt +status.stage.ninja_synthesis_execute = Ninja-Plan wird erzeugt und { $tool } ausgeführt +status.stage.graph_rendering = Graph-Artefakt wird gerendert +status.stage.graph_rendering_with_tool = { $tool } wird gerendert +status.complete = { $tool } abgeschlossen. +status.timing.summary_header = Zeitübersicht der Phasen: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Gesamtdauer der Pipeline: { $duration } +status.tool.build = Build +status.tool.clean = Bereinigung +status.tool.graph = Graph +status.tool.graph_html = Graph (HTML) +status.tool.generate = Erzeugung + +# Zeichenketten des HTML-Graph-Renderers. +graph.html.title = Netsuke-Build-Graph +graph.html.heading = Netsuke-Build-Graph +graph.html.description = Von Netsuke gerenderter Build-Graph +graph.html.outline.summary = Ziele und Abhängigkeiten (Textgliederung) +graph.html.outline.no_inputs = Keine Eingaben +graph.html.noscript.notice = JavaScript ist deaktiviert. Die Textgliederung oben enthält den vollständigen Graphen; darunter folgt der DOT-Quelltext. + +# Semantische Präfixe für die barrierefreie Ausgabe. +semantic.prefix.error = Fehler: +semantic.prefix.warning = Warnung: +semantic.prefix.success = Erfolg: +semantic.prefix.info = Info: +semantic.prefix.timing = Zeit: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Beispiele für Pluralformen für Übersetzerinnen und Übersetzer. +# Deutsch verwendet wie die Quellsprache die CLDR-Kategorien `one` und `other`. +example.files_processed = { $count -> + [one] { $count } Datei verarbeitet. + *[other] { $count } Dateien verarbeitet. +} + +example.errors_found = { $count -> + [0] Keine Fehler gefunden. + [one] { $count } Fehler gefunden. + *[other] { $count } Fehler gefunden. +} diff --git a/locales/el/messages.ftl b/locales/el/messages.ftl new file mode 100644 index 000000000..77202380f --- /dev/null +++ b/locales/el/messages.ftl @@ -0,0 +1,399 @@ +# Πόροι τοπικοποίησης για τη γραμμή εντολών του Netsuke. + +cli.about = Το Netsuke μεταγλωττίζει δηλωτικά YAML + Jinja σε σχέδια δόμησης Ninja. +cli.long_about = Το Netsuke μετατρέπει δηλωτικά YAML + Jinja σε αναπαραγώγιμα γραφήματα Ninja και εκτελεί το Ninja με ασφαλείς προεπιλογές. +cli.usage = { $usage } + +# Κείμενο βοήθειας για τις γενικές επιλογές. +cli.flag.file.help = Διαδρομή προς το αρχείο δηλωτικού του Netsuke που θα χρησιμοποιηθεί. +cli.flag.directory.help = Εκτέλεση σαν να είχε ξεκινήσει σε αυτόν τον κατάλογο. +cli.flag.config.help = Διαδρομή προς αρχείο ρυθμίσεων, παρακάμπτοντας την αυτόματη αναζήτηση. +cli.flag.jobs.help = Ορισμός του πλήθους των παράλληλων εργασιών δόμησης. +cli.flag.verbose.help = Ενεργοποίηση αναλυτικής διαγνωστικής καταγραφής και συνόψεων χρόνου στο τέλος. +cli.flag.locale.help = Ετικέτα γλώσσας για τα κείμενα της γραμμής εντολών (για παράδειγμα: en-US, el). +cli.flag.fetch_allow_scheme.help = Πρόσθετα σχήματα URL που επιτρέπονται στο βοήθημα fetch. +cli.flag.fetch_allow_host.help = Ονόματα κόμβων που επιτρέπονται όταν ισχύει η προεπιλεγμένη άρνηση. +cli.flag.fetch_block_host.help = Ονόματα κόμβων που αποκλείονται πάντοτε, ακόμη κι αν επιτρέπονται αλλού. +cli.flag.fetch_default_deny.help = Άρνηση όλων των κόμβων από προεπιλογή· να επιτρέπεται μόνο ο δηλωμένος κατάλογος. +cli.flag.json.help = Παραγωγή εξόδου JSON αναγνώσιμης από μηχανή. +cli.flag.no_input.help = Να μη γίνεται ποτέ ανάγνωση διαδραστικής εισόδου. +cli.flag.color.help = Πολιτική έγχρωμης εξόδου (auto, always, never). +cli.flag.emoji.help = Πολιτική για τα emoji (auto, always, never). +cli.flag.progress.help = Πολιτική εμφάνισης της προόδου (auto, always, never). +cli.flag.accessibility.help = Πολιτική προσβάσιμης εξόδου (auto, on, off). +cli.flag.default_targets.help = Προεπιλεγμένοι στόχοι δόμησης όταν δεν ορίζεται κανένας. + +# Περιγραφές υποεντολών. +cli.subcommand.build.about = Δόμηση των στόχων που ορίζονται στο δηλωτικό (προεπιλογή). +cli.subcommand.build.long_about = Δόμηση των ζητούμενων στόχων· αν δεν δοθεί κανένας, χρήση των προεπιλεγμένων στόχων του δηλωτικού. +cli.subcommand.clean.about = Αφαίρεση των τεχνουργημάτων δόμησης μέσω του Ninja. +cli.subcommand.clean.long_about = Δημιουργία προσωρινού αρχείου Ninja και έπειτα εκτέλεση του `ninja -t clean`. +cli.subcommand.graph.about = Εξαγωγή του γραφήματος εξαρτήσεων δόμησης. Η προεπιλεγμένη μορφή είναι DOT. +cli.subcommand.graph.long_about = Προβολή του αναλυμένου δηλωτικού Netsuke σε κανονικό γράφημα δόμησης και εγγραφή του ως Graphviz DOT ή, με την επιλογή `--html`, ως αυτοτελής σελίδα HTML. Χρησιμοποιήστε `--output <ΑΡΧΕΙΟ>` για εγγραφή σε αρχείο· το `-` γράφει στην τυπική έξοδο. +cli.subcommand.generate.about = Δημιουργία του δηλωτικού Ninja χωρίς εκτέλεση του Ninja. +cli.subcommand.generate.long_about = Εγγραφή του παραγόμενου δηλωτικού Ninja στην τυπική έξοδο ή σε αρχείο που επιλέγεται με `--output`. + +# Κείμενο βοήθειας για τις επιλογές της υποεντολής build. +cli.subcommand.build.flag.targets.help = Στόχοι προς δόμηση (αν παραλειφθούν, χρησιμοποιούνται οι προεπιλογές του δηλωτικού). + +# Κείμενο βοήθειας για τις επιλογές της υποεντολής graph. +cli.subcommand.graph.flag.html.help = Απόδοση του γραφήματος ως αυτοτελούς σελίδας HTML αντί για μορφή DOT. +cli.subcommand.graph.flag.output.help = Εγγραφή του τεχνουργήματος γραφήματος στο ΑΡΧΕΙΟ· χρησιμοποιήστε `-` για την τυπική έξοδο. + +# Κείμενο βοήθειας για τις επιλογές της υποεντολής generate. +cli.subcommand.generate.flag.output.help = Εγγραφή του παραγόμενου δηλωτικού Ninja στο ΑΡΧΕΙΟ αντί για την τυπική έξοδο. + +# Σφάλματα ελέγχου στη γραμμή εντολών. +cli.validation.jobs.invalid_number = Το { $value } δεν είναι έγκυρος αριθμός. +cli.validation.jobs.out_of_range = Το πλήθος των εργασιών πρέπει να βρίσκεται μεταξύ { $min } και { $max }. +cli.validation.scheme.empty = Το σχήμα δεν πρέπει να είναι κενό. +cli.validation.scheme.invalid_start = Το σχήμα «{ $scheme }» πρέπει να ξεκινά με γράμμα ASCII. +cli.validation.scheme.invalid = Μη έγκυρο σχήμα «{ $scheme }». +cli.validation.locale.empty = Η ετικέτα γλώσσας δεν πρέπει να είναι κενή. +cli.validation.locale.invalid = Μη έγκυρη ετικέτα γλώσσας «{ $locale }». +cli.validation.color.invalid = Μη έγκυρη πολιτική χρώματος «{ $value }». Έγκυρες επιλογές: auto, always, never. +cli.validation.emoji.invalid = Μη έγκυρη πολιτική emoji «{ $value }». Έγκυρες επιλογές: auto, always, never. +cli.validation.progress.invalid = Μη έγκυρη πολιτική προόδου «{ $value }». Έγκυρες επιλογές: auto, always, never. +cli.validation.accessibility.invalid = Μη έγκυρη πολιτική προσβασιμότητας «{ $value }». Έγκυρες επιλογές: auto, on, off. +cli.validation.config.expected_object = Οι τιμές της γραμμής εντολών έπρεπε να σειριοποιηθούν σε αντικείμενο· ελήφθη { $value }. + +# Μηνύματα σφάλματος του Clap. +clap-error-missing-argument = Λείπει υποχρεωτικό όρισμα: { $argument } +clap-error-missing-subcommand = Λείπει υποεντολή. Διαθέσιμες επιλογές: { $valid_subcommands } +clap-error-unknown-argument = Άγνωστο όρισμα: { $argument } +clap-error-invalid-value = Μη έγκυρη τιμή για το { $argument }: { $value } +clap-error-invalid-subcommand = Άγνωστη υποεντολή: { $subcommand } +# Σημείωση: το value-validation διατυπώνεται διαφορετικά από το invalid-value +# ώστε να ξεχωρίζουν τα σφάλματα ιδιαίτερων ελεγκτών +# (ErrorKind::ValueValidation) από τις ασυμφωνίες τύπων +# (ErrorKind::InvalidValue). +clap-error-value-validation = Ο έλεγχος απέτυχε για το { $argument }: { $value } + +# Σφάλματα και συμφραζόμενα της εκτέλεσης. +runner.manifest.not_found = Το δηλωτικό «{ $manifest_name }» δεν βρέθηκε στον κατάλογο { $directory }. +runner.manifest.not_found.help = Βεβαιωθείτε ότι το δηλωτικό υπάρχει ή δώστε `--file` με τη σωστή διαδρομή. +runner.manifest.path_missing_name = Η διαδρομή δηλωτικού «{ $path }» δεν έχει όνομα αρχείου. +runner.manifest.path_utf8 = Η διαδρομή δηλωτικού «{ $path }» δεν είναι έγκυρο UTF-8. +runner.manifest.directory_utf8 = Η διαδρομή του καταλόγου δηλωτικού «{ $path }» δεν είναι έγκυρο UTF-8. +runner.manifest.directory_label = κατάλογος `{ $directory }` +runner.manifest.current_directory_label = ο τρέχων κατάλογος +runner.context.network_policy = Δεν ήταν δυνατή η κατασκευή της πολιτικής δικτύου. +runner.context.load_manifest = Δεν ήταν δυνατή η φόρτωση του δηλωτικού από { $path }. +runner.context.serialise_manifest = Δεν ήταν δυνατή η σειριοποίηση του δηλωτικού. +runner.context.build_graph = Δεν ήταν δυνατή η κατασκευή γραφήματος από το δηλωτικό. +runner.context.generate_ninja = Δεν ήταν δυνατή η δημιουργία του δηλωτικού Ninja. +runner.context.render_graph = Δεν ήταν δυνατή η απόδοση του τεχνουργήματος γραφήματος. + +runner.io.create_temp_file = Δεν ήταν δυνατή η δημιουργία του προσωρινού αρχείου Ninja. +runner.io.write_temp_ninja = Δεν ήταν δυνατή η εγγραφή του προσωρινού αρχείου Ninja. +runner.io.flush_temp_ninja = Δεν ήταν δυνατή η εκκένωση της ενδιάμεσης μνήμης του προσωρινού αρχείου Ninja. +runner.io.sync_temp_ninja = Δεν ήταν δυνατός ο συγχρονισμός του προσωρινού αρχείου Ninja. +runner.io.create_parent_dir = Δεν ήταν δυνατή η δημιουργία του γονικού καταλόγου { $path }. +runner.io.create_ninja_file = Δεν ήταν δυνατή η δημιουργία του αρχείου Ninja στο { $path }. +runner.io.write_ninja_file = Δεν ήταν δυνατή η εγγραφή του αρχείου Ninja στο { $path }. +runner.io.flush_ninja_file = Δεν ήταν δυνατή η εκκένωση της ενδιάμεσης μνήμης του αρχείου Ninja στο { $path }. +runner.io.sync_ninja_file = Δεν ήταν δυνατός ο συγχρονισμός του αρχείου Ninja στο { $path }. +runner.io.open_ambient_dir = Δεν ήταν δυνατό το άνοιγμα του περιβάλλοντος καταλόγου. +runner.io.no_existing_ancestor = Δεν υπάρχει γονικός κατάλογος για το { $path }. +runner.io.derive_relative_path = Δεν ήταν δυνατή η εξαγωγή της σχετικής διαδρομής Ninja. +runner.io.non_utf8_path = Οι διαδρομές που δεν είναι UTF-8 δεν υποστηρίζονται (διαδρομή: { $path }). +runner.io.write_stdout = Δεν ήταν δυνατή η εγγραφή του δηλωτικού Ninja στην τυπική έξοδο. +runner.io.flush_stdout = Δεν ήταν δυνατή η εκκένωση της τυπικής εξόδου. + +# Διαγνωστικά δηλωτικού. +manifest.parse = Η ανάλυση του δηλωτικού απέτυχε. +manifest.structure_error = Σφάλμα δομής του δηλωτικού στο { $name }: { $details } +manifest.yaml.parse = Σφάλμα ανάλυσης YAML στη γραμμή { $line }, στήλη { $column }: { $details } +manifest.yaml.label = μη έγκυρο YAML +manifest.yaml.hint.tabs = Το YAML δεν επιτρέπει στηλοθέτες· χρησιμοποιήστε κενά για την εσοχή. +manifest.yaml.hint.list_item = Τα στοιχεία λίστας YAML πρέπει να ξεκινούν με «-» και να έχουν σωστή εσοχή. +manifest.yaml.hint.expected_colon = Αυτό μοιάζει με καταχώριση αντιστοίχισης· λείπει «:» μετά το κλειδί. +manifest.yaml.hint.mapping_values = Οι αντιστοιχίσεις YAML απαιτούν τιμή μετά το «:» (ή ένθετο μπλοκ). +manifest.yaml.hint.invalid_token = Το λεκτικό YAML είναι μη έγκυρο ή απροσδόκητο. +manifest.yaml.hint.escape = Διαφύγετε τις ανάστροφες καθέτους ή αφαιρέστε τις μη έγκυρες ακολουθίες διαφυγής. +manifest.env.missing = Η απαιτούμενη μεταβλητή περιβάλλοντος «{ $name }» δεν έχει οριστεί. +manifest.env.invalid_utf8 = Η μεταβλητή περιβάλλοντος «{ $name }» περιέχει μη έγκυρο UTF-8. +manifest.vars.not_object = Το `vars` του δηλωτικού πρέπει να είναι αντιστοίχιση ή αντικείμενο. +manifest.read_failed = Δεν ήταν δυνατή η ανάγνωση του δηλωτικού από { $path }. +manifest.resolve_workspace_root = Δεν ήταν δυνατός ο προσδιορισμός της ρίζας του χώρου εργασίας. +manifest.workspace_non_utf8 = Η ριζική διαδρομή του χώρου εργασίας «{ $path }» δεν είναι έγκυρο UTF-8. +manifest.path_non_utf8 = Η διαδρομή του δηλωτικού «{ $manifest }» δεν είναι έγκυρο UTF-8: { $path }. +manifest.path_missing_name = Η διαδρομή δηλωτικού «{ $path }» δεν έχει όνομα αρχείου. +manifest.open_workspace_failed = Δεν ήταν δυνατό το άνοιγμα του χώρου εργασίας { $workspace } για το δηλωτικό { $manifest }. +manifest.foreach.not_iterable = Η έκφραση `foreach` δεν είναι επαναλήψιμη. +manifest.foreach.serialise_item = Δεν ήταν δυνατή η σειριοποίηση του στοιχείου της `foreach`. +manifest.when.empty = Η έκφραση `when` δεν πρέπει να είναι κενή. +manifest.when.eval_error = Δεν ήταν δυνατή η αποτίμηση της έκφρασης `when` «{ $expr }». +manifest.when.template_error = Δεν ήταν δυνατή η απόδοση του προτύπου `when` «{ $expr }». +manifest.target.vars_not_object = Το `vars` του στόχου πρέπει να είναι αντικείμενο· ελήφθη { $value }. +manifest.vars.entry_not_object = Μια καταχώριση `vars` του δηλωτικού πρέπει να είναι αντικείμενο. +manifest.field_not_string = Το πεδίο «{ $field }» πρέπει να είναι συμβολοσειρά. +manifest.expression.parse_error = Δεν ήταν δυνατή η ανάλυση της έκφρασης { $name }. +manifest.expression.eval_error = Δεν ήταν δυνατή η αποτίμηση της έκφρασης { $name }. + +# Διαγνωστικά μακροεντολών του δηλωτικού. +manifest.macro.signature_missing_identifier = Από την υπογραφή της μακροεντολής λείπει αναγνωριστικό. +manifest.macro.signature_missing_params = Από την υπογραφή της μακροεντολής λείπουν παράμετροι. +manifest.macro.compile_failed = Δεν ήταν δυνατή η μεταγλώττιση της μακροεντολής { $name }. +manifest.macro.sequence_invalid = Οι μακροεντολές πρέπει να ορίζονται ως αντιστοίχιση ονομάτων σε πρότυπα. +manifest.macro.register_failed = Δεν ήταν δυνατή η καταχώριση των μακροεντολών του δηλωτικού. +manifest.macro.not_initialised = Το περιβάλλον μακροεντολών δεν έχει αρχικοποιηθεί. +manifest.macro.caller_invalid = Ο καλών της μακροεντολής πρέπει να είναι συμβολοσειρά. +manifest.macro.template_load_failed = Δεν ήταν δυνατή η φόρτωση του προτύπου της μακροεντολής. +manifest.macro.init_failed = Δεν ήταν δυνατή η αρχικοποίηση του περιβάλλοντος μακροεντολών. +manifest.macro.missing = Η μακροεντολή { $name } λείπει. + +# Σφάλματα μοτίβων glob στο δηλωτικό. +manifest.glob.unmatched_brace = Μη έγκυρο μοτίβο glob «{ $pattern }»: «{ $character }» χωρίς ταίρι στη θέση { $position }. +manifest.glob.invalid_pattern = Μη έγκυρο μοτίβο glob «{ $pattern }»: { $detail }. +manifest.glob.unknown_pattern_error = άγνωστο σφάλμα μοτίβου. +manifest.glob.io_failed = Το glob απέτυχε για «{ $pattern }»: { $detail }. +manifest.glob.unknown_io_error = άγνωστο σφάλμα εισόδου/εξόδου. + +# Σφάλματα της ενδιάμεσης αναπαράστασης. +ir.rule_not_found = Ο κανόνας «{ $rule }» στον οποίο παραπέμπει ο στόχος «{ $target }» δεν βρέθηκε. +ir.multiple_rules = Ο στόχος «{ $target }» πρέπει να παραπέμπει σε έναν μόνο κανόνα· ελήφθη { $rules }. +ir.empty_rule = Ο στόχος «{ $target }» πρέπει να παραπέμπει σε κανόνα. +ir.duplicate_outputs = Εντοπίστηκαν διπλότυπες έξοδοι: { $outputs }. +ir.circular_dependency = Εντοπίστηκε κυκλική εξάρτηση: { $cycle }. +ir.action_serialisation = Δεν ήταν δυνατή η σειριοποίηση της ενέργειας: { $details }. +ir.invalid_command = Μη έγκυρη παρεμβολή στην εντολή: { $snippet }. + +# Σφάλματα παραγωγής αρχείων Ninja. +ninja_gen.missing_action = Λείπει η ενέργεια «{ $id }» στην οποία παραπέμπει ακμή δόμησης. +ninja_gen.format = Δεν ήταν δυνατή η μορφοποίηση της εξόδου του δηλωτικού Ninja. + +# Έλεγχος μοτίβων κόμβων. +host_pattern.empty = Το μοτίβο κόμβου δεν πρέπει να είναι κενό. +host_pattern.contains_scheme = Το μοτίβο κόμβου «{ $pattern }» δεν πρέπει να περιέχει σχήμα URL. +host_pattern.contains_slash = Το μοτίβο κόμβου «{ $pattern }» δεν πρέπει να περιέχει «/». +host_pattern.missing_suffix = Το μοτίβο κόμβου «{ $pattern }» πρέπει να περιέχει κατάληξη μετά το «*.». +host_pattern.empty_label = Το μοτίβο κόμβου «{ $pattern }» περιέχει κενή ετικέτα. +host_pattern.invalid_chars = Το μοτίβο κόμβου «{ $pattern }» περιέχει μη έγκυρους χαρακτήρες. +host_pattern.invalid_label_edge = Οι ετικέτες του μοτίβου κόμβου «{ $pattern }» δεν πρέπει να ξεκινούν ή να τελειώνουν με «-». +host_pattern.label_too_long = Το μοτίβο κόμβου «{ $pattern }» περιέχει ετικέτα μεγαλύτερη από 63 χαρακτήρες. +host_pattern.too_long = Το μοτίβο κόμβου «{ $pattern }» υπερβαίνει το όριο των 255 χαρακτήρων. + +# Πολιτική δικτύου. +network_policy.scheme.empty = Το σχήμα δεν πρέπει να είναι κενό. +network_policy.scheme.invalid = Το σχήμα «{ $scheme }» περιέχει μη έγκυρους χαρακτήρες. +network_policy.allowlist.empty = Ο κατάλογος επιτρεπόμενων κόμβων δεν πρέπει να είναι κενός. +network_policy.scheme.not_allowed = Το σχήμα «{ $scheme }» δεν επιτρέπεται. +network_policy.missing_host = Από τη διεύθυνση URL λείπει ο κόμβος. +network_policy.host.blocked = Ο κόμβος «{ $host }» αποκλείεται από την πολιτική. +network_policy.host.not_allowlisted = Ο κόμβος «{ $host }» δεν περιλαμβάνεται στον κατάλογο επιτρεπόμενων. + +# Ρυθμίσεις της τυπικής βιβλιοθήκης. +stdlib.config.default_fetch_cache_invalid = Η προεπιλεγμένη διαδρομή της κρυφής μνήμης fetch πρέπει να είναι σχετική. +stdlib.config.default_which_cache_invalid = Η προεπιλεγμένη χωρητικότητα της κρυφής μνήμης which πρέπει να είναι θετική. +stdlib.config.workspace_root_absolute = Η ριζική διαδρομή του χώρου εργασίας πρέπει να είναι απόλυτη. +stdlib.config.fetch_response_limit_positive = Το όριο απόκρισης του fetch πρέπει να είναι θετικό. +stdlib.config.command_output_limit_positive = Το όριο καταγραφής της εξόδου εντολών πρέπει να είναι θετικό. +stdlib.config.command_stream_limit_positive = Το όριο ροής εντολών πρέπει να είναι θετικό. +stdlib.config.which_cache_capacity_positive = Η χωρητικότητα της κρυφής μνήμης which πρέπει να είναι θετική. +stdlib.config.skip_dir_empty = Οι καταχωρίσεις καταλόγων προς παράλειψη δεν πρέπει να είναι κενές. +stdlib.config.skip_dir_navigation = Οι καταχωρίσεις καταλόγων προς παράλειψη δεν πρέπει να περιέχουν «..». +stdlib.config.skip_dir_separator = Οι καταχωρίσεις καταλόγων προς παράλειψη δεν πρέπει να περιέχουν διαχωριστικά διαδρομής. +stdlib.config.fetch_cache_empty = Η διαδρομή της κρυφής μνήμης fetch δεν πρέπει να είναι κενή. +stdlib.config.fetch_cache_not_relative = Η διαδρομή της κρυφής μνήμης fetch πρέπει να είναι σχετική· ελήφθη { $path }. +stdlib.config.fetch_cache_escapes = Η διαδρομή της κρυφής μνήμης fetch δεν πρέπει να βγαίνει έξω από τον χώρο εργασίας: { $path }. +stdlib.config.open_workspace_root = Δεν ήταν δυνατό το άνοιγμα του τρέχοντος καταλόγου ως ρίζας του χώρου εργασίας της stdlib. +stdlib.config.resolve_cwd = Δεν ήταν δυνατός ο προσδιορισμός του τρέχοντος καταλόγου ως ρίζας του χώρου εργασίας της stdlib. +stdlib.config.cwd_non_utf8 = Ο τρέχων κατάλογος περιέχει τμήματα που δεν είναι UTF-8: { $path }. + +# Διαγνωστικά του βοηθήματος fetch. +stdlib.fetch.url_invalid = Μη έγκυρη διεύθυνση URL «{ $url }»: { $details }. +stdlib.fetch.disallowed = Η διεύθυνση URL «{ $url }» δεν επιτρέπεται: { $details }. +stdlib.fetch.failed = Δεν ήταν δυνατή η λήψη του «{ $url }»: { $details }. +stdlib.fetch.cache_read_failed = Δεν ήταν δυνατή η ανάγνωση της καταχώρισης κρυφής μνήμης «{ $name }»: { $details }. +stdlib.fetch.cache_open_failed = Δεν ήταν δυνατό το άνοιγμα της καταχώρισης κρυφής μνήμης «{ $name }»: { $details }. +stdlib.fetch.response_read_failed = Δεν ήταν δυνατή η ανάγνωση της απόκρισης από «{ $url }»: { $details }. +stdlib.fetch.response_buffer_overflow = Υπερχείλιση ενδιάμεσης μνήμης κατά την ανάγνωση του «{ $url }». +stdlib.fetch.cache_write_failed = Δεν ήταν δυνατή η εγγραφή της κρυφής μνήμης για «{ $url }»: { $details }. +stdlib.fetch.response_limit_exceeded = Η απόκριση από «{ $url }» υπερέβη το όριο των { $limit } byte. +stdlib.fetch.cache_limit_exceeded = Η αποθηκευμένη απόκριση «{ $name }» υπερέβη το όριο των { $limit } byte. +stdlib.fetch.io_failed = Η ενέργεια «{ $action }» απέτυχε για { $path }: { $details }. +stdlib.fetch.action.sync_cache = συγχρονισμός της κρυφής μνήμης fetch +stdlib.fetch.action.create_cache_dir = δημιουργία του καταλόγου κρυφής μνήμης fetch +stdlib.fetch.action.open_cache_dir = άνοιγμα του καταλόγου κρυφής μνήμης fetch +stdlib.fetch.action.stat_cache = ανάκτηση στοιχείων της καταχώρισης κρυφής μνήμης fetch +stdlib.fetch.action.open_cache_entry = άνοιγμα της καταχώρισης κρυφής μνήμης fetch + +# Διαγνωστικά του βοηθήματος εντολών. +stdlib.command.location = εντολή «{ $command }» στο πρότυπο «{ $template }» +stdlib.command.spawn_failed = Η { $location } δεν μπόρεσε να εκκινήσει: { $details }. +stdlib.command.io_failed = Η { $location } απέτυχε: { $details }. +stdlib.command.closed_input_early = Η είσοδος έκλεισε πριν ολοκληρωθεί η εγγραφή προς την εντολή. +stdlib.command.broken_pipe = Διακοπή διοχέτευσης ενώ εκτελούνταν η { $location }: { $details }. +stdlib.command.terminated_by_signal = Η { $location } τερματίστηκε από σήμα. +stdlib.command.exited_with_status = Η { $location } τερματίστηκε με κατάσταση { $status }. +stdlib.command.output_limit_exceeded = Η { $location } υπερέβη το όριο { $mode } των { $limit } byte για { $stream }. +stdlib.command.timeout = Η { $location } υπερέβη το χρονικό όριο των { $seconds } δευτερολέπτων. +stdlib.command.exit_status_suffix = (κατάσταση εξόδου { $status }) +stdlib.command.signal_suffix = (τερματίστηκε από σήμα) +stdlib.command.shell.empty = Η εντολή κελύφους δεν πρέπει να είναι κενή. +stdlib.command.grep.empty_pattern = Το μοτίβο του grep δεν πρέπει να είναι κενό. +stdlib.command.grep.flags_not_string = Οι σημαίες του grep πρέπει να είναι συμβολοσειρές. +stdlib.command.quote.invalid = Δεν ήταν δυνατή η χρήση εισαγωγικών για το { $arg }: { $details }. +stdlib.command.quote.line_break = Ορίσματα με χαρακτήρες επαναφοράς ή αλλαγής γραμμής δεν μπορούν να τεθούν με ασφάλεια σε εισαγωγικά. +stdlib.command.input_undefined = Η τιμή εισόδου δεν είναι ορισμένη. +stdlib.command.tempfile.root_required = Για τη δημιουργία προσωρινών αρχείων εντολών απαιτείται η ρίζα του χώρου εργασίας. +stdlib.command.tempfile.create_failed = Δεν ήταν δυνατή η δημιουργία του προσωρινού αρχείου εντολής: { $details }. +stdlib.command.options.invalid_utf8 = Το κλειδί επιλογής της εντολής πρέπει να είναι έγκυρο UTF-8. +stdlib.command.option.mode_not_string = Η κατάσταση εξόδου πρέπει να είναι συμβολοσειρά. +stdlib.command.options.invalid_type = Οι επιλογές της εντολής πρέπει να είναι αντικείμενο. +stdlib.command.output.mode_unsupported = Μη υποστηριζόμενη κατάσταση εξόδου «{ $mode }». +stdlib.command.output.mode.capture = καταγραφή +stdlib.command.output.mode.streaming = συνεχής ροή +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Διαγνωστικά του βοηθήματος διαδρομών. +stdlib.path.io.failed = Η ενέργεια «{ $action }» απέτυχε για { $path } ({ $label }). +stdlib.path.io.failed_with_detail = Η ενέργεια «{ $action }» απέτυχε για { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = Η ενέργεια «{ $action }» απέτυχε για { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = δεν βρέθηκε +stdlib.path.io.permission_denied = δεν επιτρέπεται η πρόσβαση +stdlib.path.io.already_exists = υπάρχει ήδη +stdlib.path.io.invalid_input = μη έγκυρη είσοδος +stdlib.path.io.invalid_data = μη έγκυρα δεδομένα +stdlib.path.io.timed_out = έληξε το χρονικό όριο +stdlib.path.io.interrupted = διακόπηκε +stdlib.path.io.would_block = θα προκαλούσε φραγή +stdlib.path.io.write_zero = γράφτηκαν μηδέν byte +stdlib.path.io.unexpected_eof = απροσδόκητο τέλος αρχείου +stdlib.path.io.broken_pipe = διακοπή διοχέτευσης +stdlib.path.io.connection_refused = άρνηση σύνδεσης +stdlib.path.io.connection_reset = επαναφορά σύνδεσης +stdlib.path.io.connection_aborted = ματαίωση σύνδεσης +stdlib.path.io.not_connected = χωρίς σύνδεση +stdlib.path.io.addr_in_use = η διεύθυνση χρησιμοποιείται ήδη +stdlib.path.io.addr_not_available = η διεύθυνση δεν είναι διαθέσιμη +stdlib.path.io.out_of_memory = εξαντλήθηκε η μνήμη +stdlib.path.io.unsupported = δεν υποστηρίζεται +stdlib.path.io.file_too_large = το αρχείο είναι πολύ μεγάλο +stdlib.path.io.resource_busy = ο πόρος είναι απασχολημένος +stdlib.path.io.executable_busy = το εκτελέσιμο είναι απασχολημένο +stdlib.path.io.deadlock = αδιέξοδο +stdlib.path.io.crosses_devices = διασχίζει συσκευές +stdlib.path.io.too_many_links = υπερβολικά πολλοί σύνδεσμοι +stdlib.path.io.invalid_filename = μη έγκυρο όνομα αρχείου +stdlib.path.io.arg_list_too_long = υπερβολικά μεγάλος κατάλογος ορισμάτων +stdlib.path.io.stale_handle = παρωχημένος χειριστής δικτυακού αρχείου +stdlib.path.io.storage_full = ο χώρος αποθήκευσης είναι πλήρης +stdlib.path.io.not_seekable = δεν επιτρέπει αναζήτηση θέσης +stdlib.path.io.network_down = το δίκτυο δεν λειτουργεί +stdlib.path.io.network_unreachable = το δίκτυο δεν είναι προσβάσιμο +stdlib.path.io.host_unreachable = ο κόμβος δεν είναι προσβάσιμος +stdlib.path.io.other = σφάλμα εισόδου/εξόδου +stdlib.path.action.canonicalize = κανονικοποίηση +stdlib.path.action.open_directory = άνοιγμα καταλόγου +stdlib.path.action.stat = ανάκτηση στοιχείων +stdlib.path.action.read = ανάγνωση +stdlib.path.action.open_file = άνοιγμα αρχείου +stdlib.path.with_suffix.empty_separator = Το with_suffix απαιτεί μη κενό διαχωριστικό. +stdlib.path.relative_to.mismatch = Το { $path } δεν είναι σχετικό ως προς το { $root }. +stdlib.path.expanduser.unsupported = Η ανάπτυξη του ~ για συγκεκριμένο χρήστη δεν υποστηρίζεται. +stdlib.path.expanduser.no_home = Δεν είναι δυνατή η ανάπτυξη του ~: δεν έχει οριστεί καμία μεταβλητή περιβάλλοντος για τον προσωπικό κατάλογο. +stdlib.path.contents.unsupported_encoding = Μη υποστηριζόμενη κωδικοποίηση «{ $encoding }». +stdlib.path.hash.unsupported_algorithm = Μη υποστηριζόμενος αλγόριθμος κατακερματισμού «{ $algorithm }». +stdlib.path.hash.unsupported_algorithm_legacy = Μη υποστηριζόμενος αλγόριθμος κατακερματισμού «{ $algorithm }» (ενεργοποιήστε τη δυνατότητα «{ $feature }»). + +# Διαγνωστικά των βοηθημάτων συλλογών. +stdlib.collections.flatten.expected_sequence = Το flatten περίμενε στοιχεία ακολουθίας αλλά βρήκε { $kind }. +stdlib.collections.group_by.empty_attribute = Το group_by απαιτεί μη κενό γνώρισμα. +stdlib.collections.group_by.unresolved = Το group_by δεν μπόρεσε να εντοπίσει το «{ $attr }» σε στοιχείο τύπου { $kind }. + +# Διαγνωστικά των βοηθημάτων χρόνου. +stdlib.time.offset.invalid = Η μετατόπιση now «{ $offset }» δεν είναι έγκυρη: αναμενόταν «+HH:MM[:SS]» ή «Z». +stdlib.time.timedelta.overflow = Υπερχείλιση timedelta κατά την πρόσθεση του { $component }. +stdlib.time.label.weeks = εβδομάδες +stdlib.time.label.days = ημέρες +stdlib.time.label.hours = ώρες +stdlib.time.label.minutes = λεπτά +stdlib.time.label.seconds = δευτερόλεπτα +stdlib.time.label.milliseconds = χιλιοστά του δευτερολέπτου +stdlib.time.label.microseconds = εκατομμυριοστά του δευτερολέπτου +stdlib.time.label.nanoseconds = δισεκατομμυριοστά του δευτερολέπτου + +# Διαγνωστικά του βοηθήματος which. +stdlib.which.not_found = [netsuke::jinja::which::not_found] η εντολή «{ $command }» δεν βρέθηκε μετά τον έλεγχο { $count } καταχωρίσεων του PATH. Προεπισκόπηση: { $preview } +stdlib.which.not_found.hint.cwd_auto = Τα κενά τμήματα του PATH αγνοούνται· χρησιμοποιήστε cwd_mode="auto" για να συμπεριληφθεί ο κατάλογος εργασίας. +stdlib.which.not_found.hint.cwd_always = Ορίστε cwd_mode="always" για να συμπεριληφθεί ο τρέχων κατάλογος. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] η εντολή «{ $command }» στο «{ $path }» λείπει ή δεν είναι εκτελέσιμη. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = <κενό> +stdlib.which.path_entry.non_utf8 = Η καταχώριση αρ. { $index } του PATH περιέχει χαρακτήρες που δεν είναι UTF-8· το Netsuke απαιτεί διαδρομές UTF-8. +stdlib.which.command.empty = Το which απαιτεί μη κενή συμβολοσειρά. +stdlib.which.cwd_mode.invalid = Το cwd_mode πρέπει να είναι «auto», «always» ή «never»· ελήφθη «{ $mode }». +stdlib.which.cwd.resolve_failed = Δεν ήταν δυνατός ο προσδιορισμός του τρέχοντος καταλόγου: { $details }. +stdlib.which.cwd.non_utf8 = Ο τρέχων κατάλογος περιέχει τμήματα που δεν είναι UTF-8. +stdlib.which.canonicalize_failed = Δεν ήταν δυνατή η κανονικοποίηση του «{ $path }»: { $details }. +stdlib.which.is_executable = Δεν ήταν δυνατός ο έλεγχος του αν το «{ $path }» είναι εκτελέσιμο: { $details }. +stdlib.which.canonicalize_non_utf8 = Η κανονική διαδρομή περιέχει τμήματα που δεν είναι UTF-8. +stdlib.which.workspace_non_utf8 = Η διαδρομή του χώρου εργασίας περιέχει τμήματα που δεν είναι UTF-8 κατά την επίλυση της εντολής «{ $command }»: { $path }. +stdlib.which.walkdir_error = Σφάλμα διάσχισης του χώρου εργασίας κατά την επίλυση της εντολής: { $details }. + +# Καταχώριση της τυπικής βιβλιοθήκης. +stdlib.register.open_dir = Δεν ήταν δυνατό το άνοιγμα του τρέχοντος καταλόγου για την καταχώριση της stdlib. +stdlib.register.resolve_dir = Δεν ήταν δυνατός ο προσδιορισμός του τρέχοντος καταλόγου για την καταχώριση της stdlib. +stdlib.register.dir_non_utf8 = Ο τρέχων κατάλογος περιέχει τμήματα που δεν είναι UTF-8: { $path }. + +# Αναφορά κατάστασης για την προσβάσιμη έξοδο. +status.state.pending = σε αναμονή +status.state.running = σε εξέλιξη +status.state.done = ολοκληρώθηκε +status.state.failed = απέτυχε +status.stage.label = Στάδιο { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Εργασία { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Ανάγνωση του αρχείου δηλωτικού +status.stage.initial_yaml_parsing = Ανάλυση του εγγράφου YAML +status.stage.template_expansion = Ανάπτυξη των οδηγιών προτύπου +status.stage.final_rendering = Αποσειριοποίηση και απόδοση των τιμών του δηλωτικού +status.stage.ir_generation_validation = Κατασκευή και έλεγχος του γραφήματος εξαρτήσεων +status.stage.ninja_synthesis = Σύνθεση του σχεδίου δόμησης Ninja +status.stage.ninja_synthesis_execute = Σύνθεση του σχεδίου Ninja και εκτέλεση του { $tool } +status.stage.graph_rendering = Απόδοση του τεχνουργήματος γραφήματος +status.stage.graph_rendering_with_tool = Απόδοση του { $tool } +status.complete = { $tool }: ολοκληρώθηκε. +status.timing.summary_header = Σύνοψη χρόνων ανά στάδιο: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Συνολικός χρόνος της ροής: { $duration } +status.tool.build = Δόμηση +status.tool.clean = Καθαρισμός +status.tool.graph = Γράφημα +status.tool.graph_html = Γράφημα (HTML) +status.tool.generate = Δημιουργία + +# Κείμενα της απόδοσης του γραφήματος σε HTML. +graph.html.title = Γράφημα δόμησης του Netsuke +graph.html.heading = Γράφημα δόμησης του Netsuke +graph.html.description = Γράφημα δόμησης που αποδόθηκε από το Netsuke +graph.html.outline.summary = Στόχοι και εξαρτήσεις (διάρθρωση σε κείμενο) +graph.html.outline.no_inputs = Καμία είσοδος +graph.html.noscript.notice = Η JavaScript είναι απενεργοποιημένη. Η παραπάνω διάρθρωση σε κείμενο περιέχει ολόκληρο το γράφημα· ακολουθεί ο πηγαίος κώδικας DOT. + +# Σημασιολογικά προθέματα για την προσβάσιμη έξοδο. +semantic.prefix.error = Σφάλμα: +semantic.prefix.warning = Προειδοποίηση: +semantic.prefix.success = Επιτυχία: +semantic.prefix.info = Πληροφορία: +semantic.prefix.timing = Χρόνος: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Παραδείγματα πληθυντικών μορφών για μεταφραστές. +# Τα ελληνικά χρησιμοποιούν τις κατηγορίες CLDR `one` και `other`, όπως και η +# γλώσσα προέλευσης. +example.files_processed = { $count -> + [one] Επεξεργάστηκε { $count } αρχείο. + *[other] Επεξεργάστηκαν { $count } αρχεία. +} + +example.errors_found = { $count -> + [0] Δεν βρέθηκαν σφάλματα. + [one] Βρέθηκε { $count } σφάλμα. + *[other] Βρέθηκαν { $count } σφάλματα. +} diff --git a/locales/en-GB/messages.ftl b/locales/en-GB/messages.ftl new file mode 100644 index 000000000..9b3896307 --- /dev/null +++ b/locales/en-GB/messages.ftl @@ -0,0 +1,398 @@ +# Netsuke CLI localisation resources (British English, Oxford spelling). + +cli.about = Netsuke compiles YAML + Jinja manifests into Ninja build plans. +cli.long_about = Netsuke transforms YAML + Jinja manifests into reproducible Ninja graphs and runs Ninja with safe defaults. +cli.usage = { $usage } + +# Root-level flag help text. +cli.flag.file.help = Path to the Netsuke manifest file to use. +cli.flag.directory.help = Run as if started in this directory. +cli.flag.config.help = Path to a configuration file, bypassing automatic discovery. +cli.flag.jobs.help = Set the number of parallel build jobs. +cli.flag.verbose.help = Enable verbose diagnostic logging and completion timing summaries. +cli.flag.locale.help = Locale tag for CLI copy (for example: en-GB, es-ES). +cli.flag.fetch_allow_scheme.help = Additional URL schemes allowed for the fetch helper. +cli.flag.fetch_allow_host.help = Hostnames that are permitted when default deny is enabled. +cli.flag.fetch_block_host.help = Hostnames that are always blocked, even when allowed elsewhere. +cli.flag.fetch_default_deny.help = Deny all hosts by default; only allow the declared allowlist. +cli.flag.json.help = Emit machine-readable JSON output. +cli.flag.no_input.help = Never read interactive input. +cli.flag.color.help = Colour output policy (auto, always, never). +cli.flag.emoji.help = Emoji policy (auto, always, never). +cli.flag.progress.help = Progress rendering policy (auto, always, never). +cli.flag.accessibility.help = Accessible output policy (auto, on, off). +cli.flag.default_targets.help = Default build targets when none are specified. + +# Subcommand descriptions. +cli.subcommand.build.about = Build targets defined in the manifest (default). +cli.subcommand.build.long_about = Build the requested targets; when none are provided, use the manifest defaults. +cli.subcommand.clean.about = Remove build artefacts via Ninja. +cli.subcommand.clean.long_about = Generate a temporary Ninja file, then run `ninja -t clean`. +cli.subcommand.graph.about = Emit the build dependency graph. Default format is DOT. +cli.subcommand.graph.long_about = Project the parsed Netsuke manifest into a canonical build graph and write it as Graphviz DOT, or as a self-contained HTML page with `--html`. Use `--output ` to write to a file; `-` writes to stdout. +cli.subcommand.generate.about = Generate the Ninja manifest without running Ninja. +cli.subcommand.generate.long_about = Write the generated Ninja manifest to stdout, or to a file selected with `--output`. + +# Build subcommand flag help text. +cli.subcommand.build.flag.targets.help = Targets to build (uses manifest defaults if omitted). + +# Graph subcommand flag help text. +cli.subcommand.graph.flag.html.help = Render the graph as a self-contained HTML page instead of DOT. +cli.subcommand.graph.flag.output.help = Write the graph artefact to FILE; use `-` for stdout. + +# Generate subcommand flag help text. +cli.subcommand.generate.flag.output.help = Write the generated Ninja manifest to FILE instead of stdout. + +# CLI validation errors. +cli.validation.jobs.invalid_number = { $value } is not a valid number. +cli.validation.jobs.out_of_range = Jobs must be between { $min } and { $max }. +cli.validation.scheme.empty = Scheme must not be empty. +cli.validation.scheme.invalid_start = Scheme '{ $scheme }' must start with an ASCII letter. +cli.validation.scheme.invalid = Invalid scheme '{ $scheme }'. +cli.validation.locale.empty = Locale must not be empty. +cli.validation.locale.invalid = Invalid locale '{ $locale }'. +cli.validation.color.invalid = Invalid colour policy '{ $value }'. Valid options: auto, always, never. +cli.validation.emoji.invalid = Invalid emoji policy '{ $value }'. Valid options: auto, always, never. +cli.validation.progress.invalid = Invalid progress policy '{ $value }'. Valid options: auto, always, never. +cli.validation.accessibility.invalid = Invalid accessibility policy '{ $value }'. Valid options: auto, on, off. +cli.validation.config.expected_object = Expected parsed CLI values to serialise to an object, got { $value }. + +# Clap error messages. +clap-error-missing-argument = Missing required argument: { $argument } +clap-error-missing-subcommand = Missing subcommand. Available options: { $valid_subcommands } +clap-error-unknown-argument = Unknown argument: { $argument } +clap-error-invalid-value = Invalid value for { $argument }: { $value } +clap-error-invalid-subcommand = Unknown subcommand: { $subcommand } +# Note: value-validation uses distinct wording from invalid-value to differentiate +# custom validator failures (ErrorKind::ValueValidation) from type mismatches +# (ErrorKind::InvalidValue). +clap-error-value-validation = Validation failed for { $argument }: { $value } + +# Runner errors and contexts. +runner.manifest.not_found = Manifest '{ $manifest_name }' not found in { $directory }. +runner.manifest.not_found.help = Ensure the manifest exists or pass `--file` with the correct path. +runner.manifest.path_missing_name = Manifest path '{ $path }' has no file name. +runner.manifest.path_utf8 = Manifest path '{ $path }' is not valid UTF-8. +runner.manifest.directory_utf8 = Manifest directory path '{ $path }' is not valid UTF-8. +runner.manifest.directory_label = directory `{ $directory }` +runner.manifest.current_directory_label = the current directory +runner.context.network_policy = Failed to build the network policy. +runner.context.load_manifest = Failed to load manifest at { $path }. +runner.context.serialise_manifest = Failed to serialise manifest. +runner.context.build_graph = Failed to build graph from the manifest. +runner.context.generate_ninja = Failed to generate the Ninja manifest. +runner.context.render_graph = Failed to render the graph artefact. + +runner.io.create_temp_file = Failed to create temporary Ninja file. +runner.io.write_temp_ninja = Failed to write temporary Ninja file. +runner.io.flush_temp_ninja = Failed to flush temporary Ninja file. +runner.io.sync_temp_ninja = Failed to sync temporary Ninja file. +runner.io.create_parent_dir = Failed to create parent directory { $path }. +runner.io.create_ninja_file = Failed to create Ninja file at { $path }. +runner.io.write_ninja_file = Failed to write Ninja file at { $path }. +runner.io.flush_ninja_file = Failed to flush Ninja file at { $path }. +runner.io.sync_ninja_file = Failed to sync Ninja file at { $path }. +runner.io.open_ambient_dir = Failed to open ambient directory. +runner.io.no_existing_ancestor = No existing ancestor directory for { $path }. +runner.io.derive_relative_path = Failed to derive relative Ninja path. +runner.io.non_utf8_path = Non-UTF-8 path is not supported (path: { $path }). +runner.io.write_stdout = Failed to write Ninja manifest to stdout. +runner.io.flush_stdout = Failed to flush stdout. + +# Manifest diagnostics. +manifest.parse = Manifest parse failed. +manifest.structure_error = Manifest structure error in { $name }: { $details } +manifest.yaml.parse = YAML parse error at line { $line }, column { $column }: { $details } +manifest.yaml.label = invalid YAML +manifest.yaml.hint.tabs = YAML does not permit tabs; use spaces for indentation. +manifest.yaml.hint.list_item = YAML list items must start with a '-' and be properly indented. +manifest.yaml.hint.expected_colon = This looks like a mapping entry; missing a ':' after the key. +manifest.yaml.hint.mapping_values = YAML mappings require values after ':' (or a nested block). +manifest.yaml.hint.invalid_token = YAML token is invalid or unexpected. +manifest.yaml.hint.escape = Escape backslashes or remove invalid escape sequences. +manifest.env.missing = Required environment variable '{ $name }' is not set. +manifest.env.invalid_utf8 = Environment variable '{ $name }' contains invalid UTF-8. +manifest.vars.not_object = Manifest `vars` must be a map/object. +manifest.read_failed = Failed to read manifest at { $path }. +manifest.resolve_workspace_root = Failed to resolve workspace root. +manifest.workspace_non_utf8 = Workspace root path '{ $path }' is not valid UTF-8. +manifest.path_non_utf8 = Manifest '{ $manifest }' path is not valid UTF-8: { $path }. +manifest.path_missing_name = Manifest path '{ $path }' has no file name. +manifest.open_workspace_failed = Failed to open workspace { $workspace } for manifest { $manifest }. +manifest.foreach.not_iterable = `foreach` expression is not iterable. +manifest.foreach.serialise_item = Failed to serialise foreach item. +manifest.when.empty = `when` expression must not be empty. +manifest.when.eval_error = Failed to evaluate `when` expression '{ $expr }'. +manifest.when.template_error = Failed to render `when` template '{ $expr }'. +manifest.target.vars_not_object = Target `vars` must be an object, got { $value }. +manifest.vars.entry_not_object = Manifest `vars` entry must be an object. +manifest.field_not_string = Field '{ $field }' must be a string. +manifest.expression.parse_error = Failed to parse { $name } expression. +manifest.expression.eval_error = Failed to evaluate { $name } expression. + +# Manifest macro diagnostics. +manifest.macro.signature_missing_identifier = Macro signature is missing an identifier. +manifest.macro.signature_missing_params = Macro signature is missing parameters. +manifest.macro.compile_failed = Failed to compile macro { $name }. +manifest.macro.sequence_invalid = Macros must be defined as a mapping of names to templates. +manifest.macro.register_failed = Failed to register manifest macros. +manifest.macro.not_initialised = Macro environment is not initialised. +manifest.macro.caller_invalid = Macro caller must be a string. +manifest.macro.template_load_failed = Failed to load macro template. +manifest.macro.init_failed = Failed to initialise macro environment. +manifest.macro.missing = Macro { $name } is missing. + +# Manifest glob errors. +manifest.glob.unmatched_brace = Invalid glob pattern '{ $pattern }': unmatched '{ $character }' at position { $position }. +manifest.glob.invalid_pattern = Invalid glob pattern '{ $pattern }': { $detail }. +manifest.glob.unknown_pattern_error = unknown pattern error. +manifest.glob.io_failed = Glob failed for '{ $pattern }': { $detail }. +manifest.glob.unknown_io_error = unknown I/O error. + +# IR errors. +ir.rule_not_found = Rule '{ $rule }' referenced by target '{ $target }' was not found. +ir.multiple_rules = Target '{ $target }' must reference a single rule, got { $rules }. +ir.empty_rule = Target '{ $target }' must reference a rule. +ir.duplicate_outputs = Duplicate outputs detected: { $outputs }. +ir.circular_dependency = Circular dependency detected: { $cycle }. +ir.action_serialisation = Failed to serialise action: { $details }. +ir.invalid_command = Invalid command interpolation: { $snippet }. + +# Ninja generation errors. +ninja_gen.missing_action = Missing action '{ $id }' referenced by a build edge. +ninja_gen.format = Failed to format the Ninja manifest output. + +# Host pattern validation. +host_pattern.empty = Host pattern must not be empty. +host_pattern.contains_scheme = Host pattern '{ $pattern }' must not include a URL scheme. +host_pattern.contains_slash = Host pattern '{ $pattern }' must not include '/'. +host_pattern.missing_suffix = Host pattern '{ $pattern }' must include a suffix after '*.'. +host_pattern.empty_label = Host pattern '{ $pattern }' contains an empty label. +host_pattern.invalid_chars = Host pattern '{ $pattern }' contains invalid characters. +host_pattern.invalid_label_edge = Host pattern '{ $pattern }' labels must not start or end with '-'. +host_pattern.label_too_long = Host pattern '{ $pattern }' contains a label longer than 63 characters. +host_pattern.too_long = Host pattern '{ $pattern }' exceeds the 255 character limit. + +# Network policy. +network_policy.scheme.empty = Scheme must not be empty. +network_policy.scheme.invalid = Scheme '{ $scheme }' contains invalid characters. +network_policy.allowlist.empty = Host allowlist must not be empty. +network_policy.scheme.not_allowed = Scheme '{ $scheme }' is not allowed. +network_policy.missing_host = URL is missing a host. +network_policy.host.blocked = Host '{ $host }' is blocked by policy. +network_policy.host.not_allowlisted = Host '{ $host }' is not on the allowlist. + +# Stdlib configuration. +stdlib.config.default_fetch_cache_invalid = Default fetch cache path must be relative. +stdlib.config.default_which_cache_invalid = Default which cache capacity must be positive. +stdlib.config.workspace_root_absolute = Workspace root path must be absolute. +stdlib.config.fetch_response_limit_positive = Fetch response limit must be positive. +stdlib.config.command_output_limit_positive = Command output capture limit must be positive. +stdlib.config.command_stream_limit_positive = Command stream limit must be positive. +stdlib.config.which_cache_capacity_positive = Which cache capacity must be positive. +stdlib.config.skip_dir_empty = Skip directory entries must not be empty. +stdlib.config.skip_dir_navigation = Skip directory entries must not contain '..'. +stdlib.config.skip_dir_separator = Skip directory entries must not contain path separators. +stdlib.config.fetch_cache_empty = Fetch cache path must not be empty. +stdlib.config.fetch_cache_not_relative = Fetch cache path must be relative, got { $path }. +stdlib.config.fetch_cache_escapes = Fetch cache path must not escape the workspace: { $path }. +stdlib.config.open_workspace_root = Failed to open the current directory as the stdlib workspace root. +stdlib.config.resolve_cwd = Failed to resolve the current directory for the stdlib workspace root. +stdlib.config.cwd_non_utf8 = Current directory contains non-UTF-8 components: { $path }. + +# Fetch helper diagnostics. +stdlib.fetch.url_invalid = Invalid URL '{ $url }': { $details }. +stdlib.fetch.disallowed = URL '{ $url }' is disallowed: { $details }. +stdlib.fetch.failed = Failed to fetch '{ $url }': { $details }. +stdlib.fetch.cache_read_failed = Failed to read fetch cache entry '{ $name }': { $details }. +stdlib.fetch.cache_open_failed = Failed to open fetch cache entry '{ $name }': { $details }. +stdlib.fetch.response_read_failed = Failed to read response from '{ $url }': { $details }. +stdlib.fetch.response_buffer_overflow = Response buffer overflow while reading '{ $url }'. +stdlib.fetch.cache_write_failed = Failed to write cache for '{ $url }': { $details }. +stdlib.fetch.response_limit_exceeded = Response from '{ $url }' exceeded limit { $limit } bytes. +stdlib.fetch.cache_limit_exceeded = Cached response '{ $name }' exceeded limit { $limit } bytes. +stdlib.fetch.io_failed = { $action } failed for { $path }: { $details }. +stdlib.fetch.action.sync_cache = sync fetch cache +stdlib.fetch.action.create_cache_dir = create fetch cache directory +stdlib.fetch.action.open_cache_dir = open fetch cache directory +stdlib.fetch.action.stat_cache = stat fetch cache entry +stdlib.fetch.action.open_cache_entry = open fetch cache entry + +# Command helper diagnostics. +stdlib.command.location = command '{ $command }' in template '{ $template }' +stdlib.command.spawn_failed = Failed to spawn { $location }: { $details }. +stdlib.command.io_failed = { $location } failed: { $details }. +stdlib.command.closed_input_early = Input closed early while writing to the command. +stdlib.command.broken_pipe = Broken pipe while running { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } terminated by signal. +stdlib.command.exited_with_status = { $location } exited with status { $status }. +stdlib.command.output_limit_exceeded = { $location } exceeded { $mode } { $stream } limit of { $limit } bytes. +stdlib.command.timeout = { $location } timed out after { $seconds } seconds. +stdlib.command.exit_status_suffix = (exit status { $status }) +stdlib.command.signal_suffix = (terminated by signal) +stdlib.command.shell.empty = Shell command must not be empty. +stdlib.command.grep.empty_pattern = Grep pattern must not be empty. +stdlib.command.grep.flags_not_string = Grep flags must be strings. +stdlib.command.quote.invalid = Failed to quote { $arg }: { $details }. +stdlib.command.quote.line_break = Arguments containing carriage returns or line feeds cannot be safely quoted. +stdlib.command.input_undefined = Input value is undefined. +stdlib.command.tempfile.root_required = Workspace root is required to create command temp files. +stdlib.command.tempfile.create_failed = Failed to create command tempfile: { $details }. +stdlib.command.options.invalid_utf8 = Command option key must be valid UTF-8. +stdlib.command.option.mode_not_string = Output mode must be a string. +stdlib.command.options.invalid_type = Command options must be an object. +stdlib.command.output.mode_unsupported = Unsupported output mode '{ $mode }'. +stdlib.command.output.mode.capture = capture +stdlib.command.output.mode.streaming = streaming +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Path helper diagnostics. +stdlib.path.io.failed = { $action } failed for { $path } ({ $label }). +stdlib.path.io.failed_with_detail = { $action } failed for { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = { $action } failed for { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = not found +stdlib.path.io.permission_denied = permission denied +stdlib.path.io.already_exists = already exists +stdlib.path.io.invalid_input = invalid input +stdlib.path.io.invalid_data = invalid data +stdlib.path.io.timed_out = timed out +stdlib.path.io.interrupted = interrupted +stdlib.path.io.would_block = would block +stdlib.path.io.write_zero = zero bytes written +stdlib.path.io.unexpected_eof = unexpected end of file +stdlib.path.io.broken_pipe = broken pipe +stdlib.path.io.connection_refused = connection refused +stdlib.path.io.connection_reset = connection reset +stdlib.path.io.connection_aborted = connection aborted +stdlib.path.io.not_connected = not connected +stdlib.path.io.addr_in_use = address in use +stdlib.path.io.addr_not_available = address not available +stdlib.path.io.out_of_memory = out of memory +stdlib.path.io.unsupported = unsupported +stdlib.path.io.file_too_large = file too large +stdlib.path.io.resource_busy = resource busy +stdlib.path.io.executable_busy = executable busy +stdlib.path.io.deadlock = deadlock +stdlib.path.io.crosses_devices = crosses devices +stdlib.path.io.too_many_links = too many links +stdlib.path.io.invalid_filename = invalid filename +stdlib.path.io.arg_list_too_long = argument list too long +stdlib.path.io.stale_handle = stale network file handle +stdlib.path.io.storage_full = storage full +stdlib.path.io.not_seekable = not seekable +stdlib.path.io.network_down = network down +stdlib.path.io.network_unreachable = network unreachable +stdlib.path.io.host_unreachable = host unreachable +stdlib.path.io.other = I/O error +stdlib.path.action.canonicalize = canonicalise +stdlib.path.action.open_directory = open directory +stdlib.path.action.stat = stat +stdlib.path.action.read = read +stdlib.path.action.open_file = open file +stdlib.path.with_suffix.empty_separator = with_suffix requires a non-empty separator. +stdlib.path.relative_to.mismatch = { $path } is not relative to { $root }. +stdlib.path.expanduser.unsupported = User-specific ~ expansion is unsupported. +stdlib.path.expanduser.no_home = Cannot expand ~: no home directory environment variables are set. +stdlib.path.contents.unsupported_encoding = Unsupported encoding '{ $encoding }'. +stdlib.path.hash.unsupported_algorithm = Unsupported hash algorithm '{ $algorithm }'. +stdlib.path.hash.unsupported_algorithm_legacy = Unsupported hash algorithm '{ $algorithm }' (enable feature '{ $feature }'). + +# Collection helper diagnostics. +stdlib.collections.flatten.expected_sequence = Flatten expected sequence items but found { $kind }. +stdlib.collections.group_by.empty_attribute = group_by requires a non-empty attribute. +stdlib.collections.group_by.unresolved = group_by could not resolve '{ $attr }' on item of kind { $kind }. + +# Time helper diagnostics. +stdlib.time.offset.invalid = now offset '{ $offset }' is invalid: expected '+HH:MM[:SS]' or 'Z'. +stdlib.time.timedelta.overflow = timedelta overflow when adding { $component }. +stdlib.time.label.weeks = weeks +stdlib.time.label.days = days +stdlib.time.label.hours = hours +stdlib.time.label.minutes = minutes +stdlib.time.label.seconds = seconds +stdlib.time.label.milliseconds = milliseconds +stdlib.time.label.microseconds = microseconds +stdlib.time.label.nanoseconds = nanoseconds + +# Which helper diagnostics. +stdlib.which.not_found = [netsuke::jinja::which::not_found] command '{ $command }' not found after checking { $count } PATH entries. Preview: { $preview } +stdlib.which.not_found.hint.cwd_auto = Empty PATH segments are ignored; use cwd_mode="auto" to include the working directory. +stdlib.which.not_found.hint.cwd_always = Set cwd_mode="always" to include the current directory. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] command '{ $command }' at '{ $path }' is missing or not executable. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = PATH entry #{ $index } contains non-UTF-8 characters; Netsuke requires UTF-8 paths. +stdlib.which.command.empty = which requires a non-empty string. +stdlib.which.cwd_mode.invalid = cwd_mode must be 'auto', 'always', or 'never', got '{ $mode }'. +stdlib.which.cwd.resolve_failed = Failed to resolve current directory: { $details }. +stdlib.which.cwd.non_utf8 = Current directory contains non-UTF-8 components. +stdlib.which.canonicalize_failed = Failed to canonicalise '{ $path }': { $details }. +stdlib.which.is_executable = Failed to inspect whether '{ $path }' is executable: { $details }. +stdlib.which.canonicalize_non_utf8 = Canonical path contains non-UTF-8 components. +stdlib.which.workspace_non_utf8 = Workspace path contains non-UTF-8 components while resolving command '{ $command }': { $path }. +stdlib.which.walkdir_error = Workspace traversal error while resolving command: { $details }. + +# Stdlib registration. +stdlib.register.open_dir = Failed to open current directory for stdlib registration. +stdlib.register.resolve_dir = Failed to resolve current directory for stdlib registration. +stdlib.register.dir_non_utf8 = Current directory contains non-UTF-8 components: { $path }. + +# Status reporting for accessible output mode. +status.state.pending = pending +status.state.running = in progress +status.state.done = done +status.state.failed = failed +status.stage.label = Stage { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Task { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Reading manifest file +status.stage.initial_yaml_parsing = Parsing YAML document +status.stage.template_expansion = Expanding template directives +status.stage.final_rendering = Deserialising and rendering manifest values +status.stage.ir_generation_validation = Building and validating dependency graph +status.stage.ninja_synthesis = Synthesising Ninja build plan +status.stage.ninja_synthesis_execute = Synthesising Ninja plan and executing { $tool } +status.stage.graph_rendering = Rendering graph artefact +status.stage.graph_rendering_with_tool = Rendering { $tool } +status.complete = { $tool } complete. +status.timing.summary_header = Stage timing summary: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Total pipeline time: { $duration } +status.tool.build = Build +status.tool.clean = Clean +status.tool.graph = Graph +status.tool.graph_html = Graph (HTML) +status.tool.generate = Generate + +# Graph HTML renderer strings. +graph.html.title = Netsuke build graph +graph.html.heading = Netsuke build graph +graph.html.description = Build graph rendered by Netsuke +graph.html.outline.summary = Targets and dependencies (text outline) +graph.html.outline.no_inputs = No inputs +graph.html.noscript.notice = JavaScript is disabled. The text outline above is the full graph; the DOT source follows. + +# Semantic prefixes for accessible output. +semantic.prefix.error = Error: +semantic.prefix.warning = Warning: +semantic.prefix.success = Success: +semantic.prefix.info = Info: +semantic.prefix.timing = Timing: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Plural form examples for translators. +# British English shares the CLDR `one`/`other` categories with the source +# locale, so only the wording differs. +example.files_processed = { $count -> + [one] Processed { $count } file. + *[other] Processed { $count } files. +} + +example.errors_found = { $count -> + [0] No errors found. + [one] { $count } error found. + *[other] { $count } errors found. +} diff --git a/locales/es-419/messages.ftl b/locales/es-419/messages.ftl new file mode 100644 index 000000000..4bb4a06cc --- /dev/null +++ b/locales/es-419/messages.ftl @@ -0,0 +1,400 @@ +# Recursos de localización para la CLI de Netsuke (español de América Latina). + +cli.about = Netsuke compila manifiestos YAML + Jinja en planes de compilación de Ninja. +cli.long_about = Netsuke transforma manifiestos YAML + Jinja en grafos de Ninja reproducibles y ejecuta Ninja con valores predeterminados seguros. +cli.usage = { $usage } + +# Texto de ayuda de las opciones globales. +cli.flag.file.help = Ruta al archivo de manifiesto de Netsuke que se va a usar. +cli.flag.directory.help = Ejecutar como si se hubiera iniciado en este directorio. +cli.flag.config.help = Ruta a un archivo de configuración, omitiendo la detección automática. +cli.flag.jobs.help = Establecer la cantidad de trabajos de compilación en paralelo. +cli.flag.verbose.help = Habilitar registros de diagnóstico detallados y resúmenes de tiempos al finalizar. +cli.flag.locale.help = Etiqueta de idioma para los textos de la CLI (por ejemplo: en-US, es-419). +cli.flag.fetch_allow_scheme.help = Esquemas de URL adicionales permitidos para el asistente fetch. +cli.flag.fetch_allow_host.help = Nombres de host permitidos cuando el rechazo predeterminado está activo. +cli.flag.fetch_block_host.help = Nombres de host siempre bloqueados, incluso si se permiten en otro lugar. +cli.flag.fetch_default_deny.help = Rechazar todos los hosts de forma predeterminada; permitir solo la lista declarada. +cli.flag.json.help = Emitir salida JSON legible por máquinas. +cli.flag.no_input.help = Nunca leer entrada interactiva. +cli.flag.color.help = Política de color en la salida (auto, always, never). +cli.flag.emoji.help = Política de emojis (auto, always, never). +cli.flag.progress.help = Política de visualización del progreso (auto, always, never). +cli.flag.accessibility.help = Política de salida accesible (auto, on, off). +cli.flag.default_targets.help = Objetivos de compilación predeterminados cuando no se indica ninguno. + +# Descripciones de los subcomandos. +cli.subcommand.build.about = Compilar los objetivos definidos en el manifiesto (predeterminado). +cli.subcommand.build.long_about = Compilar los objetivos solicitados; si no se indican, usar los predeterminados del manifiesto. +cli.subcommand.clean.about = Eliminar los artefactos de compilación mediante Ninja. +cli.subcommand.clean.long_about = Generar un archivo Ninja temporal y luego ejecutar `ninja -t clean`. +cli.subcommand.graph.about = Emitir el grafo de dependencias de compilación. El formato predeterminado es DOT. +cli.subcommand.graph.long_about = Proyectar el manifiesto de Netsuke analizado en un grafo de compilación canónico y escribirlo como Graphviz DOT, o como página HTML autónoma con `--html`. Use `--output ` para escribir en un archivo; `-` escribe en stdout. +cli.subcommand.generate.about = Generar el manifiesto de Ninja sin ejecutar Ninja. +cli.subcommand.generate.long_about = Escribir el manifiesto de Ninja generado en stdout o en el archivo elegido con `--output`. + +# Texto de ayuda de las opciones del subcomando build. +cli.subcommand.build.flag.targets.help = Objetivos que se van a compilar (si se omite, usa los predeterminados del manifiesto). + +# Texto de ayuda de las opciones del subcomando graph. +cli.subcommand.graph.flag.html.help = Representar el grafo como página HTML autónoma en lugar de DOT. +cli.subcommand.graph.flag.output.help = Escribir el artefacto del grafo en ARCHIVO; use `-` para stdout. + +# Texto de ayuda de las opciones del subcomando generate. +cli.subcommand.generate.flag.output.help = Escribir el manifiesto de Ninja generado en ARCHIVO en lugar de stdout. + +# Errores de validación de la CLI. +cli.validation.jobs.invalid_number = { $value } no es un número válido. +cli.validation.jobs.out_of_range = La cantidad de trabajos debe estar entre { $min } y { $max }. +cli.validation.scheme.empty = El esquema no debe estar vacío. +cli.validation.scheme.invalid_start = El esquema '{ $scheme }' debe comenzar con una letra ASCII. +cli.validation.scheme.invalid = Esquema no válido '{ $scheme }'. +cli.validation.locale.empty = La etiqueta de idioma no debe estar vacía. +cli.validation.locale.invalid = Etiqueta de idioma no válida '{ $locale }'. +cli.validation.color.invalid = Política de color no válida '{ $value }'. Opciones válidas: auto, always, never. +cli.validation.emoji.invalid = Política de emojis no válida '{ $value }'. Opciones válidas: auto, always, never. +cli.validation.progress.invalid = Política de progreso no válida '{ $value }'. Opciones válidas: auto, always, never. +cli.validation.accessibility.invalid = Política de accesibilidad no válida '{ $value }'. Opciones válidas: auto, on, off. +cli.validation.config.expected_object = Se esperaba que los valores de la CLI se serializaran como un objeto, se obtuvo { $value }. + +# Mensajes de error de Clap. +clap-error-missing-argument = Falta un argumento obligatorio: { $argument } +clap-error-missing-subcommand = Falta el subcomando. Opciones disponibles: { $valid_subcommands } +clap-error-unknown-argument = Argumento desconocido: { $argument } +clap-error-invalid-value = Valor no válido para { $argument }: { $value } +clap-error-invalid-subcommand = Subcomando desconocido: { $subcommand } +# Nota: value-validation usa una redacción distinta de invalid-value para +# diferenciar los errores de validadores personalizados +# (ErrorKind::ValueValidation) de las incompatibilidades de tipo +# (ErrorKind::InvalidValue). +clap-error-value-validation = La validación falló para { $argument }: { $value } + +# Errores y contextos del ejecutor. +runner.manifest.not_found = No se encontró el manifiesto '{ $manifest_name }' en { $directory }. +runner.manifest.not_found.help = Verifique que el manifiesto exista o indique `--file` con la ruta correcta. +runner.manifest.path_missing_name = La ruta del manifiesto '{ $path }' no tiene nombre de archivo. +runner.manifest.path_utf8 = La ruta del manifiesto '{ $path }' no es UTF-8 válido. +runner.manifest.directory_utf8 = La ruta del directorio del manifiesto '{ $path }' no es UTF-8 válido. +runner.manifest.directory_label = directorio `{ $directory }` +runner.manifest.current_directory_label = el directorio actual +runner.context.network_policy = No se pudo construir la política de red. +runner.context.load_manifest = No se pudo cargar el manifiesto en { $path }. +runner.context.serialise_manifest = No se pudo serializar el manifiesto. +runner.context.build_graph = No se pudo construir el grafo a partir del manifiesto. +runner.context.generate_ninja = No se pudo generar el manifiesto de Ninja. +runner.context.render_graph = No se pudo representar el artefacto del grafo. + +runner.io.create_temp_file = No se pudo crear el archivo Ninja temporal. +runner.io.write_temp_ninja = No se pudo escribir el archivo Ninja temporal. +runner.io.flush_temp_ninja = No se pudo vaciar el archivo Ninja temporal. +runner.io.sync_temp_ninja = No se pudo sincronizar el archivo Ninja temporal. +runner.io.create_parent_dir = No se pudo crear el directorio principal { $path }. +runner.io.create_ninja_file = No se pudo crear el archivo Ninja en { $path }. +runner.io.write_ninja_file = No se pudo escribir el archivo Ninja en { $path }. +runner.io.flush_ninja_file = No se pudo vaciar el archivo Ninja en { $path }. +runner.io.sync_ninja_file = No se pudo sincronizar el archivo Ninja en { $path }. +runner.io.open_ambient_dir = No se pudo abrir el directorio del entorno. +runner.io.no_existing_ancestor = No existe un directorio antecesor para { $path }. +runner.io.derive_relative_path = No se pudo derivar la ruta relativa de Ninja. +runner.io.non_utf8_path = No se admiten rutas que no sean UTF-8 (ruta: { $path }). +runner.io.write_stdout = No se pudo escribir el manifiesto de Ninja en stdout. +runner.io.flush_stdout = No se pudo vaciar stdout. + +# Diagnósticos del manifiesto. +manifest.parse = Falló el análisis del manifiesto. +manifest.structure_error = Error de estructura del manifiesto en { $name }: { $details } +manifest.yaml.parse = Error de análisis de YAML en la línea { $line }, columna { $column }: { $details } +manifest.yaml.label = YAML no válido +manifest.yaml.hint.tabs = YAML no permite tabulaciones; use espacios para la sangría. +manifest.yaml.hint.list_item = Los elementos de lista de YAML deben comenzar con '-' y estar bien sangrados. +manifest.yaml.hint.expected_colon = Esto parece una entrada de mapeo; falta un ':' después de la clave. +manifest.yaml.hint.mapping_values = Los mapeos de YAML requieren un valor después de ':' (o un bloque anidado). +manifest.yaml.hint.invalid_token = El token de YAML no es válido o es inesperado. +manifest.yaml.hint.escape = Escape las barras invertidas o elimine las secuencias de escape no válidas. +manifest.env.missing = La variable de entorno requerida '{ $name }' no está definida. +manifest.env.invalid_utf8 = La variable de entorno '{ $name }' contiene UTF-8 no válido. +manifest.vars.not_object = `vars` del manifiesto debe ser un mapa u objeto. +manifest.read_failed = No se pudo leer el manifiesto en { $path }. +manifest.resolve_workspace_root = No se pudo resolver la raíz del espacio de trabajo. +manifest.workspace_non_utf8 = La ruta raíz del espacio de trabajo '{ $path }' no es UTF-8 válido. +manifest.path_non_utf8 = La ruta del manifiesto '{ $manifest }' no es UTF-8 válido: { $path }. +manifest.path_missing_name = La ruta del manifiesto '{ $path }' no tiene nombre de archivo. +manifest.open_workspace_failed = No se pudo abrir el espacio de trabajo { $workspace } para el manifiesto { $manifest }. +manifest.foreach.not_iterable = La expresión `foreach` no es iterable. +manifest.foreach.serialise_item = No se pudo serializar el elemento de `foreach`. +manifest.when.empty = La expresión `when` no debe estar vacía. +manifest.when.eval_error = No se pudo evaluar la expresión `when` '{ $expr }'. +manifest.when.template_error = No se pudo representar la plantilla `when` '{ $expr }'. +manifest.target.vars_not_object = `vars` del objetivo debe ser un objeto, se obtuvo { $value }. +manifest.vars.entry_not_object = Una entrada `vars` del manifiesto debe ser un objeto. +manifest.field_not_string = El campo '{ $field }' debe ser una cadena. +manifest.expression.parse_error = No se pudo analizar la expresión { $name }. +manifest.expression.eval_error = No se pudo evaluar la expresión { $name }. + +# Diagnósticos de las macros del manifiesto. +manifest.macro.signature_missing_identifier = A la firma de la macro le falta un identificador. +manifest.macro.signature_missing_params = A la firma de la macro le faltan parámetros. +manifest.macro.compile_failed = No se pudo compilar la macro { $name }. +manifest.macro.sequence_invalid = Las macros deben definirse como un mapeo de nombres a plantillas. +manifest.macro.register_failed = No se pudieron registrar las macros del manifiesto. +manifest.macro.not_initialised = El entorno de macros no está inicializado. +manifest.macro.caller_invalid = El llamador de la macro debe ser una cadena. +manifest.macro.template_load_failed = No se pudo cargar la plantilla de la macro. +manifest.macro.init_failed = No se pudo inicializar el entorno de macros. +manifest.macro.missing = Falta la macro { $name }. + +# Errores de glob del manifiesto. +manifest.glob.unmatched_brace = Patrón glob no válido '{ $pattern }': '{ $character }' sin pareja en la posición { $position }. +manifest.glob.invalid_pattern = Patrón glob no válido '{ $pattern }': { $detail }. +manifest.glob.unknown_pattern_error = error de patrón desconocido. +manifest.glob.io_failed = El glob falló para '{ $pattern }': { $detail }. +manifest.glob.unknown_io_error = error de E/S desconocido. + +# Errores de la representación intermedia. +ir.rule_not_found = No se encontró la regla '{ $rule }' referenciada por el objetivo '{ $target }'. +ir.multiple_rules = El objetivo '{ $target }' debe referenciar una sola regla, se obtuvo { $rules }. +ir.empty_rule = El objetivo '{ $target }' debe referenciar una regla. +ir.duplicate_outputs = Se detectaron salidas duplicadas: { $outputs }. +ir.circular_dependency = Se detectó una dependencia circular: { $cycle }. +ir.action_serialisation = No se pudo serializar la acción: { $details }. +ir.invalid_command = Interpolación de comando no válida: { $snippet }. + +# Errores de generación de Ninja. +ninja_gen.missing_action = Falta la acción '{ $id }' referenciada por una arista de compilación. +ninja_gen.format = No se pudo dar formato a la salida del manifiesto de Ninja. + +# Validación de patrones de host. +host_pattern.empty = El patrón de host no debe estar vacío. +host_pattern.contains_scheme = El patrón de host '{ $pattern }' no debe incluir un esquema de URL. +host_pattern.contains_slash = El patrón de host '{ $pattern }' no debe incluir '/'. +host_pattern.missing_suffix = El patrón de host '{ $pattern }' debe incluir un sufijo después de '*.'. +host_pattern.empty_label = El patrón de host '{ $pattern }' contiene una etiqueta vacía. +host_pattern.invalid_chars = El patrón de host '{ $pattern }' contiene caracteres no válidos. +host_pattern.invalid_label_edge = Las etiquetas del patrón de host '{ $pattern }' no deben comenzar ni terminar con '-'. +host_pattern.label_too_long = El patrón de host '{ $pattern }' contiene una etiqueta de más de 63 caracteres. +host_pattern.too_long = El patrón de host '{ $pattern }' supera el límite de 255 caracteres. + +# Política de red. +network_policy.scheme.empty = El esquema no debe estar vacío. +network_policy.scheme.invalid = El esquema '{ $scheme }' contiene caracteres no válidos. +network_policy.allowlist.empty = La lista de hosts permitidos no debe estar vacía. +network_policy.scheme.not_allowed = El esquema '{ $scheme }' no está permitido. +network_policy.missing_host = A la URL le falta el host. +network_policy.host.blocked = El host '{ $host }' está bloqueado por la política. +network_policy.host.not_allowlisted = El host '{ $host }' no está en la lista de permitidos. + +# Configuración de la biblioteca estándar. +stdlib.config.default_fetch_cache_invalid = La ruta predeterminada de la caché de fetch debe ser relativa. +stdlib.config.default_which_cache_invalid = La capacidad predeterminada de la caché de which debe ser positiva. +stdlib.config.workspace_root_absolute = La ruta raíz del espacio de trabajo debe ser absoluta. +stdlib.config.fetch_response_limit_positive = El límite de respuesta de fetch debe ser positivo. +stdlib.config.command_output_limit_positive = El límite de captura de salida de comandos debe ser positivo. +stdlib.config.command_stream_limit_positive = El límite de transmisión de comandos debe ser positivo. +stdlib.config.which_cache_capacity_positive = La capacidad de la caché de which debe ser positiva. +stdlib.config.skip_dir_empty = Las entradas de directorios omitidos no deben estar vacías. +stdlib.config.skip_dir_navigation = Las entradas de directorios omitidos no deben contener '..'. +stdlib.config.skip_dir_separator = Las entradas de directorios omitidos no deben contener separadores de ruta. +stdlib.config.fetch_cache_empty = La ruta de la caché de fetch no debe estar vacía. +stdlib.config.fetch_cache_not_relative = La ruta de la caché de fetch debe ser relativa, se obtuvo { $path }. +stdlib.config.fetch_cache_escapes = La ruta de la caché de fetch no debe salir del espacio de trabajo: { $path }. +stdlib.config.open_workspace_root = No se pudo abrir el directorio actual como raíz del espacio de trabajo de la stdlib. +stdlib.config.resolve_cwd = No se pudo resolver el directorio actual como raíz del espacio de trabajo de la stdlib. +stdlib.config.cwd_non_utf8 = El directorio actual contiene componentes que no son UTF-8: { $path }. + +# Diagnósticos del asistente fetch. +stdlib.fetch.url_invalid = URL no válida '{ $url }': { $details }. +stdlib.fetch.disallowed = La URL '{ $url }' no está permitida: { $details }. +stdlib.fetch.failed = No se pudo descargar '{ $url }': { $details }. +stdlib.fetch.cache_read_failed = No se pudo leer la entrada de caché '{ $name }': { $details }. +stdlib.fetch.cache_open_failed = No se pudo abrir la entrada de caché '{ $name }': { $details }. +stdlib.fetch.response_read_failed = No se pudo leer la respuesta de '{ $url }': { $details }. +stdlib.fetch.response_buffer_overflow = Desbordamiento del búfer al leer '{ $url }'. +stdlib.fetch.cache_write_failed = No se pudo escribir la caché para '{ $url }': { $details }. +stdlib.fetch.response_limit_exceeded = La respuesta de '{ $url }' superó el límite de { $limit } bytes. +stdlib.fetch.cache_limit_exceeded = La respuesta en caché '{ $name }' superó el límite de { $limit } bytes. +stdlib.fetch.io_failed = { $action } falló para { $path }: { $details }. +stdlib.fetch.action.sync_cache = sincronizar la caché de fetch +stdlib.fetch.action.create_cache_dir = crear el directorio de caché de fetch +stdlib.fetch.action.open_cache_dir = abrir el directorio de caché de fetch +stdlib.fetch.action.stat_cache = consultar la entrada de caché de fetch +stdlib.fetch.action.open_cache_entry = abrir la entrada de caché de fetch + +# Diagnósticos del asistente de comandos. +stdlib.command.location = comando '{ $command }' en la plantilla '{ $template }' +stdlib.command.spawn_failed = No se pudo iniciar { $location }: { $details }. +stdlib.command.io_failed = { $location } falló: { $details }. +stdlib.command.closed_input_early = La entrada se cerró antes de terminar de escribir en el comando. +stdlib.command.broken_pipe = Canalización rota al ejecutar { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } terminó por una señal. +stdlib.command.exited_with_status = { $location } salió con el estado { $status }. +stdlib.command.output_limit_exceeded = { $location } superó el límite de { $mode } de { $limit } bytes para { $stream }. +stdlib.command.timeout = { $location } excedió el tiempo de espera de { $seconds } segundos. +stdlib.command.exit_status_suffix = (estado de salida { $status }) +stdlib.command.signal_suffix = (terminado por una señal) +stdlib.command.shell.empty = El comando de shell no debe estar vacío. +stdlib.command.grep.empty_pattern = El patrón de grep no debe estar vacío. +stdlib.command.grep.flags_not_string = Las banderas de grep deben ser cadenas. +stdlib.command.quote.invalid = No se pudo entrecomillar { $arg }: { $details }. +stdlib.command.quote.line_break = Los argumentos con retornos de carro o saltos de línea no se pueden entrecomillar de forma segura. +stdlib.command.input_undefined = El valor de entrada no está definido. +stdlib.command.tempfile.root_required = Se requiere la raíz del espacio de trabajo para crear archivos temporales de comandos. +stdlib.command.tempfile.create_failed = No se pudo crear el archivo temporal del comando: { $details }. +stdlib.command.options.invalid_utf8 = La clave de una opción del comando debe ser UTF-8 válido. +stdlib.command.option.mode_not_string = El modo de salida debe ser una cadena. +stdlib.command.options.invalid_type = Las opciones del comando deben ser un objeto. +stdlib.command.output.mode_unsupported = Modo de salida no admitido '{ $mode }'. +stdlib.command.output.mode.capture = captura +stdlib.command.output.mode.streaming = transmisión +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Diagnósticos del asistente de rutas. +stdlib.path.io.failed = { $action } falló para { $path } ({ $label }). +stdlib.path.io.failed_with_detail = { $action } falló para { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = { $action } falló para { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = no encontrado +stdlib.path.io.permission_denied = permiso denegado +stdlib.path.io.already_exists = ya existe +stdlib.path.io.invalid_input = entrada no válida +stdlib.path.io.invalid_data = datos no válidos +stdlib.path.io.timed_out = se agotó el tiempo de espera +stdlib.path.io.interrupted = interrumpido +stdlib.path.io.would_block = se bloquearía +stdlib.path.io.write_zero = escritura nula +stdlib.path.io.unexpected_eof = fin de archivo inesperado +stdlib.path.io.broken_pipe = canalización rota +stdlib.path.io.connection_refused = conexión rechazada +stdlib.path.io.connection_reset = conexión restablecida +stdlib.path.io.connection_aborted = conexión anulada +stdlib.path.io.not_connected = sin conexión +stdlib.path.io.addr_in_use = dirección en uso +stdlib.path.io.addr_not_available = dirección no disponible +stdlib.path.io.out_of_memory = sin memoria +stdlib.path.io.unsupported = no admitido +stdlib.path.io.file_too_large = archivo demasiado grande +stdlib.path.io.resource_busy = recurso ocupado +stdlib.path.io.executable_busy = ejecutable ocupado +stdlib.path.io.deadlock = bloqueo mutuo +stdlib.path.io.crosses_devices = cruza dispositivos +stdlib.path.io.too_many_links = demasiados enlaces +stdlib.path.io.invalid_filename = nombre de archivo no válido +stdlib.path.io.arg_list_too_long = lista de argumentos demasiado larga +stdlib.path.io.stale_handle = descriptor de archivo de red obsoleto +stdlib.path.io.storage_full = almacenamiento lleno +stdlib.path.io.not_seekable = no admite posicionamiento +stdlib.path.io.network_down = red caída +stdlib.path.io.network_unreachable = red inalcanzable +stdlib.path.io.host_unreachable = host inalcanzable +stdlib.path.io.other = error de E/S +stdlib.path.action.canonicalize = canonicalizar +stdlib.path.action.open_directory = abrir el directorio +stdlib.path.action.stat = consultar +stdlib.path.action.read = leer +stdlib.path.action.open_file = abrir el archivo +stdlib.path.with_suffix.empty_separator = with_suffix requiere un separador no vacío. +stdlib.path.relative_to.mismatch = { $path } no es relativo a { $root }. +stdlib.path.expanduser.unsupported = La expansión de ~ para un usuario específico no es compatible. +stdlib.path.expanduser.no_home = No se puede expandir ~: no hay variables de entorno del directorio de inicio definidas. +stdlib.path.contents.unsupported_encoding = Codificación no admitida '{ $encoding }'. +stdlib.path.hash.unsupported_algorithm = Algoritmo de hash no admitido '{ $algorithm }'. +stdlib.path.hash.unsupported_algorithm_legacy = Algoritmo de hash no admitido '{ $algorithm }' (habilite la característica '{ $feature }'). + +# Diagnósticos de los asistentes de colecciones. +stdlib.collections.flatten.expected_sequence = flatten esperaba elementos de una secuencia, pero encontró { $kind }. +stdlib.collections.group_by.empty_attribute = group_by requiere un atributo no vacío. +stdlib.collections.group_by.unresolved = group_by no pudo resolver '{ $attr }' en un elemento de tipo { $kind }. + +# Diagnósticos de los asistentes de tiempo. +stdlib.time.offset.invalid = El desplazamiento de now '{ $offset }' no es válido: se esperaba '+HH:MM[:SS]' o 'Z'. +stdlib.time.timedelta.overflow = Desbordamiento de timedelta al sumar { $component }. +stdlib.time.label.weeks = semanas +stdlib.time.label.days = días +stdlib.time.label.hours = horas +stdlib.time.label.minutes = minutos +stdlib.time.label.seconds = segundos +stdlib.time.label.milliseconds = milisegundos +stdlib.time.label.microseconds = microsegundos +stdlib.time.label.nanoseconds = nanosegundos + +# Diagnósticos del asistente which. +stdlib.which.not_found = [netsuke::jinja::which::not_found] no se encontró el comando '{ $command }' tras revisar { $count } entradas de PATH. Vista previa: { $preview } +stdlib.which.not_found.hint.cwd_auto = Los segmentos vacíos de PATH se ignoran; use cwd_mode="auto" para incluir el directorio de trabajo. +stdlib.which.not_found.hint.cwd_always = Establezca cwd_mode="always" para incluir el directorio actual. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] el comando '{ $command }' en '{ $path }' no existe o no es ejecutable. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = La entrada n.º { $index } de PATH contiene caracteres que no son UTF-8; Netsuke requiere rutas UTF-8. +stdlib.which.command.empty = which requiere una cadena no vacía. +stdlib.which.cwd_mode.invalid = cwd_mode debe ser 'auto', 'always' o 'never', se obtuvo '{ $mode }'. +stdlib.which.cwd.resolve_failed = No se pudo resolver el directorio actual: { $details }. +stdlib.which.cwd.non_utf8 = El directorio actual contiene componentes que no son UTF-8. +stdlib.which.canonicalize_failed = No se pudo canonicalizar '{ $path }': { $details }. +stdlib.which.is_executable = No se pudo comprobar si '{ $path }' es ejecutable: { $details }. +stdlib.which.canonicalize_non_utf8 = La ruta canónica contiene componentes que no son UTF-8. +stdlib.which.workspace_non_utf8 = La ruta del espacio de trabajo contiene componentes que no son UTF-8 al resolver el comando '{ $command }': { $path }. +stdlib.which.walkdir_error = Error al recorrer el espacio de trabajo mientras se resolvía el comando: { $details }. + +# Registro de la biblioteca estándar. +stdlib.register.open_dir = No se pudo abrir el directorio actual para registrar la stdlib. +stdlib.register.resolve_dir = No se pudo resolver el directorio actual para registrar la stdlib. +stdlib.register.dir_non_utf8 = El directorio actual contiene componentes que no son UTF-8: { $path }. + +# Informes de estado para el modo de salida accesible. +status.state.pending = pendiente +status.state.running = en curso +status.state.done = completada +status.state.failed = fallida +status.stage.label = Etapa { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Tarea { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Leyendo el archivo de manifiesto +status.stage.initial_yaml_parsing = Analizando el documento YAML +status.stage.template_expansion = Expandiendo las directivas de plantilla +status.stage.final_rendering = Deserializando y representando los valores del manifiesto +status.stage.ir_generation_validation = Construyendo y validando el grafo de dependencias +status.stage.ninja_synthesis = Sintetizando el plan de compilación de Ninja +status.stage.ninja_synthesis_execute = Sintetizando el plan de Ninja y ejecutando { $tool } +status.stage.graph_rendering = Representando el artefacto del grafo +status.stage.graph_rendering_with_tool = Representando { $tool } +status.complete = { $tool }: operación finalizada. +status.timing.summary_header = Resumen de tiempos por etapa: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Tiempo total de la canalización: { $duration } +status.tool.build = Compilación +status.tool.clean = Limpieza +status.tool.graph = Grafo +status.tool.graph_html = Grafo (HTML) +status.tool.generate = Generación + +# Cadenas del representador HTML del grafo. +graph.html.title = Grafo de compilación de Netsuke +graph.html.heading = Grafo de compilación de Netsuke +graph.html.description = Grafo de compilación representado por Netsuke +graph.html.outline.summary = Objetivos y dependencias (esquema de texto) +graph.html.outline.no_inputs = Sin entradas +graph.html.noscript.notice = JavaScript está desactivado. El esquema de texto anterior contiene el grafo completo; a continuación sigue el código DOT. + +# Prefijos semánticos para la salida accesible. +semantic.prefix.error = Error: +semantic.prefix.warning = Advertencia: +semantic.prefix.success = Éxito: +semantic.prefix.info = Info: +semantic.prefix.timing = Tiempos: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Ejemplos de formas plurales para traductores. +# El español usa las categorías CLDR `one` y `other`, igual que el idioma +# de origen; cambian tanto la conjugación del verbo como el número del +# sustantivo. +example.files_processed = { $count -> + [one] Se procesó { $count } archivo. + *[other] Se procesaron { $count } archivos. +} + +example.errors_found = { $count -> + [0] No se encontraron errores. + [one] Se encontró { $count } error. + *[other] Se encontraron { $count } errores. +} diff --git a/locales/es-ES/messages.ftl b/locales/es-ES/messages.ftl index fc9041422..8ad1cc713 100644 --- a/locales/es-ES/messages.ftl +++ b/locales/es-ES/messages.ftl @@ -357,7 +357,7 @@ status.stage.ninja_synthesis = Sintetizando el plan de compilación Ninja status.stage.ninja_synthesis_execute = Sintetizando el plan Ninja y ejecutando { $tool } status.stage.graph_rendering = Renderizando el artefacto de grafo status.stage.graph_rendering_with_tool = Renderizando { $tool } -status.complete = { $tool } completo. +status.complete = { $tool }: operación finalizada. status.timing.summary_header = Resumen de tiempos por etapa: status.timing.stage_line = - { $label }: { $duration } status.timing.total_line = Tiempo total de la canalización: { $duration } diff --git a/locales/fa/messages.ftl b/locales/fa/messages.ftl new file mode 100644 index 000000000..f90723084 --- /dev/null +++ b/locales/fa/messages.ftl @@ -0,0 +1,397 @@ +# منابع بومی‌سازی خط فرمان Netsuke. + +cli.about = ‏Netsuke مانیفست‌های YAML + Jinja را به طرح‌های ساخت Ninja ترجمه می‌کند. +cli.long_about = ‏Netsuke مانیفست‌های YAML + Jinja را به گراف‌های تکرارپذیر Ninja تبدیل می‌کند و Ninja را با پیش‌فرض‌های ایمن اجرا می‌کند. +cli.usage = { $usage } + +# متن راهنمای گزینه‌های عمومی. +cli.flag.file.help = مسیر پرونده مانیفست Netsuke که باید به کار رود. +cli.flag.directory.help = چنان اجرا کن که گویی در این شاخه آغاز شده است. +cli.flag.config.help = مسیر یک پرونده پیکربندی، با نادیده‌گرفتن جست‌وجوی خودکار. +cli.flag.jobs.help = تعیین شمار کارهای موازی ساخت. +cli.flag.verbose.help = فعال‌کردن گزارش تشخیصی مفصل و خلاصهٔ زمان در پایان کار. +cli.flag.locale.help = برچسب زبان برای متن‌های خط فرمان (برای نمونه: en-US یا fa). +cli.flag.fetch_allow_scheme.help = طرح‌های URL افزوده که برای یاور fetch مجازند. +cli.flag.fetch_allow_host.help = نام میزبان‌هایی که هنگام فعال‌بودن ردّ پیش‌فرض مجازند. +cli.flag.fetch_block_host.help = نام میزبان‌هایی که همیشه مسدودند، حتی اگر جای دیگری مجاز باشند. +cli.flag.fetch_default_deny.help = ردّ همهٔ میزبان‌ها به‌صورت پیش‌فرض؛ تنها فهرست اعلام‌شده مجاز است. +cli.flag.json.help = خروجی JSON خوانا برای ماشین تولید کن. +cli.flag.no_input.help = هرگز ورودی تعاملی نخوان. +cli.flag.color.help = سیاست خروجی رنگی (auto، always، never). +cli.flag.emoji.help = سیاست ایموجی (auto، always، never). +cli.flag.progress.help = سیاست نمایش پیشرفت (auto، always، never). +cli.flag.accessibility.help = سیاست خروجی دسترس‌پذیر (auto، on، off). +cli.flag.default_targets.help = هدف‌های پیش‌فرض ساخت هنگامی که هدفی مشخص نشده باشد. + +# شرح زیرفرمان‌ها. +cli.subcommand.build.about = ساخت هدف‌های تعریف‌شده در مانیفست (پیش‌فرض). +cli.subcommand.build.long_about = ساخت هدف‌های خواسته‌شده؛ اگر هدفی داده نشود، هدف‌های پیش‌فرض مانیفست به کار می‌روند. +cli.subcommand.clean.about = حذف فرآورده‌های ساخت از راه Ninja. +cli.subcommand.clean.long_about = ساختن یک پروندهٔ موقت Ninja و سپس اجرای `ninja -t clean`. +cli.subcommand.graph.about = چاپ گراف وابستگی‌های ساخت. قالب پیش‌فرض DOT است. +cli.subcommand.graph.long_about = تصویرکردن مانیفست تجزیه‌شدهٔ Netsuke به یک گراف ساخت متعارف و نوشتن آن به شکل Graphviz DOT، یا با `--html` به شکل یک صفحهٔ HTML خودبسنده. برای نوشتن در پرونده از `--output <پرونده>` استفاده کنید؛ `-` در خروجی استاندارد می‌نویسد. +cli.subcommand.generate.about = تولید مانیفست Ninja بدون اجرای Ninja. +cli.subcommand.generate.long_about = نوشتن مانیفست Ninja تولیدشده در خروجی استاندارد یا در پرونده‌ای که با `--output` برگزیده می‌شود. + +# متن راهنمای گزینه‌های زیرفرمان build. +cli.subcommand.build.flag.targets.help = هدف‌هایی که باید ساخته شوند (در صورت نیامدن، پیش‌فرض‌های مانیفست به کار می‌روند). + +# متن راهنمای گزینه‌های زیرفرمان graph. +cli.subcommand.graph.flag.html.help = نمایش گراف به شکل صفحهٔ HTML خودبسنده به‌جای قالب DOT. +cli.subcommand.graph.flag.output.help = نوشتن فرآوردهٔ گراف در پرونده؛ برای خروجی استاندارد از `-` استفاده کنید. + +# متن راهنمای گزینه‌های زیرفرمان generate. +cli.subcommand.generate.flag.output.help = نوشتن مانیفست Ninja تولیدشده در پرونده به‌جای خروجی استاندارد. + +# خطاهای اعتبارسنجی خط فرمان. +cli.validation.jobs.invalid_number = ‏{ $value } عدد معتبری نیست. +cli.validation.jobs.out_of_range = شمار کارها باید میان { $min } و { $max } باشد. +cli.validation.scheme.empty = طرح نباید تهی باشد. +cli.validation.scheme.invalid_start = طرح «{ $scheme }» باید با یک حرف ASCII آغاز شود. +cli.validation.scheme.invalid = طرح نامعتبر: «{ $scheme }». +cli.validation.locale.empty = برچسب زبان نباید تهی باشد. +cli.validation.locale.invalid = برچسب زبان نامعتبر: «{ $locale }». +cli.validation.color.invalid = سیاست رنگ نامعتبر: «{ $value }». مقادیر معتبر: auto، always، never. +cli.validation.emoji.invalid = سیاست ایموجی نامعتبر: «{ $value }». مقادیر معتبر: auto، always، never. +cli.validation.progress.invalid = سیاست پیشرفت نامعتبر: «{ $value }». مقادیر معتبر: auto، always، never. +cli.validation.accessibility.invalid = سیاست دسترس‌پذیری نامعتبر: «{ $value }». مقادیر معتبر: auto، on، off. +cli.validation.config.expected_object = انتظار می‌رفت مقادیر خط فرمان به یک شیء تبدیل شوند، اما { $value } به دست آمد. + +# پیام‌های خطای Clap. +clap-error-missing-argument = آرگومان الزامی ارائه نشده است: { $argument } +clap-error-missing-subcommand = زیرفرمان وجود ندارد. گزینه‌های در دسترس: { $valid_subcommands } +clap-error-unknown-argument = آرگومان ناشناخته: { $argument } +clap-error-invalid-value = مقدار نامعتبر برای { $argument }: { $value } +clap-error-invalid-subcommand = زیرفرمان ناشناخته: { $subcommand } +# یادداشت: عبارت value-validation از invalid-value متمایز است تا خطای +# اعتبارسنج‌های سفارشی (ErrorKind::ValueValidation) از ناسازگاری نوع +# (ErrorKind::InvalidValue) بازشناخته شود. +clap-error-value-validation = اعتبارسنجی { $argument } ناکام ماند: { $value } + +# خطاها و بافتار زمان اجرا. +runner.manifest.not_found = مانیفست «{ $manifest_name }» در { $directory } یافت نشد. +runner.manifest.not_found.help = از وجود مانیفست مطمئن شوید یا `--file` را با مسیر درست بدهید. +runner.manifest.path_missing_name = مسیر مانیفست «{ $path }» نام پرونده ندارد. +runner.manifest.path_utf8 = مسیر مانیفست «{ $path }» ‏UTF-8 معتبر نیست. +runner.manifest.directory_utf8 = مسیر شاخهٔ مانیفست «{ $path }» ‏UTF-8 معتبر نیست. +runner.manifest.directory_label = شاخهٔ `{ $directory }` +runner.manifest.current_directory_label = شاخهٔ کنونی +runner.context.network_policy = ساخت سیاست شبکه ممکن نشد. +runner.context.load_manifest = بارگذاری مانیفست از { $path } ممکن نشد. +runner.context.serialise_manifest = تبدیل مانیفست به داده‌های پیاپی ممکن نشد. +runner.context.build_graph = ساخت گراف از روی مانیفست ممکن نشد. +runner.context.generate_ninja = تولید مانیفست Ninja ممکن نشد. +runner.context.render_graph = نمایش فرآوردهٔ گراف ممکن نشد. + +runner.io.create_temp_file = ساخت پروندهٔ موقت Ninja ممکن نشد. +runner.io.write_temp_ninja = نوشتن در پروندهٔ موقت Ninja ممکن نشد. +runner.io.flush_temp_ninja = تخلیهٔ میان‌گیر پروندهٔ موقت Ninja ممکن نشد. +runner.io.sync_temp_ninja = همگام‌سازی پروندهٔ موقت Ninja ممکن نشد. +runner.io.create_parent_dir = ساخت شاخهٔ والد { $path } ممکن نشد. +runner.io.create_ninja_file = ساخت پروندهٔ Ninja در { $path } ممکن نشد. +runner.io.write_ninja_file = نوشتن در پروندهٔ Ninja در { $path } ممکن نشد. +runner.io.flush_ninja_file = تخلیهٔ میان‌گیر پروندهٔ Ninja در { $path } ممکن نشد. +runner.io.sync_ninja_file = همگام‌سازی پروندهٔ Ninja در { $path } ممکن نشد. +runner.io.open_ambient_dir = گشودن شاخهٔ پیرامون ممکن نشد. +runner.io.no_existing_ancestor = برای { $path } هیچ شاخهٔ والد موجودی نیست. +runner.io.derive_relative_path = استخراج مسیر نسبی Ninja ممکن نشد. +runner.io.non_utf8_path = مسیرهایی که UTF-8 نیستند پشتیبانی نمی‌شوند (مسیر: { $path }). +runner.io.write_stdout = نوشتن مانیفست Ninja در خروجی استاندارد ممکن نشد. +runner.io.flush_stdout = تخلیهٔ میان‌گیر خروجی استاندارد ممکن نشد. + +# تشخیص‌های مانیفست. +manifest.parse = تجزیهٔ مانیفست ناکام ماند. +manifest.structure_error = خطای ساختاری مانیفست در { $name }: { $details } +manifest.yaml.parse = خطای تجزیهٔ YAML در سطر { $line }، ستون { $column }: { $details } +manifest.yaml.label = ‏YAML نامعتبر +manifest.yaml.hint.tabs = ‏YAML نویسهٔ تب را نمی‌پذیرد؛ برای تورفتگی از فاصله استفاده کنید. +manifest.yaml.hint.list_item = عضوهای فهرست YAML باید با «-» آغاز شوند و تورفتگی درست داشته باشند. +manifest.yaml.hint.expected_colon = این شبیه یک مدخل نگاشت است؛ «:» بعد از کلید جا افتاده است. +manifest.yaml.hint.mapping_values = نگاشت‌های YAML پس از «:» به یک مقدار (یا بلوک تودرتو) نیاز دارند. +manifest.yaml.hint.invalid_token = نشانهٔ YAML نامعتبر یا نابه‌جاست. +manifest.yaml.hint.escape = ممیزهای وارونه را بگریزانید یا دنباله‌های گریز نامعتبر را بردارید. +manifest.env.missing = متغیر محیطی الزامی «{ $name }» تنظیم نشده است. +manifest.env.invalid_utf8 = متغیر محیطی «{ $name }» دربردارندهٔ UTF-8 نامعتبر است. +manifest.vars.not_object = ‏`vars` در مانیفست باید نگاشت یا شیء باشد. +manifest.read_failed = خواندن مانیفست از { $path } ممکن نشد. +manifest.resolve_workspace_root = تعیین ریشهٔ فضای کاری ممکن نشد. +manifest.workspace_non_utf8 = مسیر ریشهٔ فضای کاری «{ $path }» ‏UTF-8 معتبر نیست. +manifest.path_non_utf8 = مسیر مانیفست «{ $manifest }» ‏UTF-8 معتبر نیست: { $path }. +manifest.path_missing_name = مسیر مانیفست «{ $path }» نام پرونده ندارد. +manifest.open_workspace_failed = گشودن فضای کاری { $workspace } برای مانیفست { $manifest } ممکن نشد. +manifest.foreach.not_iterable = عبارت `foreach` پیمایش‌پذیر نیست. +manifest.foreach.serialise_item = تبدیل عضو `foreach` به داده‌های پیاپی ممکن نشد. +manifest.when.empty = عبارت `when` نباید تهی باشد. +manifest.when.eval_error = ارزیابی عبارت `when` «{ $expr }» ممکن نشد. +manifest.when.template_error = نمایش قالب `when` «{ $expr }» ممکن نشد. +manifest.target.vars_not_object = ‏`vars` هدف باید شیء باشد، اما { $value } به دست آمد. +manifest.vars.entry_not_object = مدخل `vars` مانیفست باید شیء باشد. +manifest.field_not_string = میدان «{ $field }» باید رشته باشد. +manifest.expression.parse_error = تجزیهٔ عبارت { $name } ممکن نشد. +manifest.expression.eval_error = ارزیابی عبارت { $name } ممکن نشد. + +# تشخیص‌های ماکروهای مانیفست. +manifest.macro.signature_missing_identifier = امضای ماکرو شناسه ندارد. +manifest.macro.signature_missing_params = امضای ماکرو پارامتر ندارد. +manifest.macro.compile_failed = ترجمهٔ ماکروی { $name } ممکن نشد. +manifest.macro.sequence_invalid = ماکروها باید به شکل نگاشتی از نام‌ها به قالب‌ها تعریف شوند. +manifest.macro.register_failed = ثبت ماکروهای مانیفست ممکن نشد. +manifest.macro.not_initialised = محیط ماکروها راه‌اندازی نشده است. +manifest.macro.caller_invalid = فراخوانندهٔ ماکرو باید رشته باشد. +manifest.macro.template_load_failed = بارگذاری قالب ماکرو ممکن نشد. +manifest.macro.init_failed = راه‌اندازی محیط ماکروها ممکن نشد. +manifest.macro.missing = ماکروی { $name } وجود ندارد. + +# خطاهای الگوهای glob در مانیفست. +manifest.glob.unmatched_brace = الگوی glob نامعتبر «{ $pattern }»: نویسهٔ «{ $character }» در جایگاه { $position } جفت ندارد. +manifest.glob.invalid_pattern = الگوی glob نامعتبر «{ $pattern }»: { $detail }. +manifest.glob.unknown_pattern_error = خطای الگوی ناشناخته. +manifest.glob.io_failed = ‏glob برای «{ $pattern }» ناکام ماند: { $detail }. +manifest.glob.unknown_io_error = خطای ورودی/خروجی ناشناخته. + +# خطاهای بازنمایی میانی. +ir.rule_not_found = قاعدهٔ «{ $rule }» که هدف «{ $target }» به آن ارجاع می‌دهد یافت نشد. +ir.multiple_rules = هدف «{ $target }» باید تنها به یک قاعده ارجاع دهد، اما { $rules } به دست آمد. +ir.empty_rule = هدف «{ $target }» باید به یک قاعده ارجاع دهد. +ir.duplicate_outputs = خروجی‌های تکراری یافت شد: { $outputs }. +ir.circular_dependency = وابستگی چرخه‌ای یافت شد: { $cycle }. +ir.action_serialisation = تبدیل کنش به داده‌های پیاپی ممکن نشد: { $details }. +ir.invalid_command = درج نامعتبر در فرمان: { $snippet }. + +# خطاهای تولید پرونده‌های Ninja. +ninja_gen.missing_action = کنش «{ $id }» که یک یال ساخت به آن ارجاع می‌دهد وجود ندارد. +ninja_gen.format = قالب‌بندی خروجی مانیفست Ninja ممکن نشد. + +# اعتبارسنجی الگوهای میزبان. +host_pattern.empty = الگوی میزبان نباید تهی باشد. +host_pattern.contains_scheme = الگوی میزبان «{ $pattern }» نباید طرح URL داشته باشد. +host_pattern.contains_slash = الگوی میزبان «{ $pattern }» نباید «/» داشته باشد. +host_pattern.missing_suffix = الگوی میزبان «{ $pattern }» باید پس از «*.» پسوند داشته باشد. +host_pattern.empty_label = الگوی میزبان «{ $pattern }» برچسبی تهی دارد. +host_pattern.invalid_chars = الگوی میزبان «{ $pattern }» نویسه‌های نامعتبر دارد. +host_pattern.invalid_label_edge = برچسب‌های الگوی میزبان «{ $pattern }» نباید با «-» آغاز یا پایان یابند. +host_pattern.label_too_long = الگوی میزبان «{ $pattern }» برچسبی بلندتر از ۶۳ نویسه دارد. +host_pattern.too_long = الگوی میزبان «{ $pattern }» از مرز ۲۵۵ نویسه فراتر می‌رود. + +# سیاست شبکه. +network_policy.scheme.empty = طرح نباید تهی باشد. +network_policy.scheme.invalid = طرح «{ $scheme }» نویسه‌های نامعتبر دارد. +network_policy.allowlist.empty = فهرست میزبان‌های مجاز نباید تهی باشد. +network_policy.scheme.not_allowed = طرح «{ $scheme }» مجاز نیست. +network_policy.missing_host = نشانی URL میزبان ندارد. +network_policy.host.blocked = میزبان «{ $host }» بر پایهٔ سیاست مسدود است. +network_policy.host.not_allowlisted = میزبان «{ $host }» در فهرست مجاز نیست. + +# پیکربندی کتابخانهٔ استاندارد. +stdlib.config.default_fetch_cache_invalid = مسیر پیش‌فرض نهانگاه fetch باید نسبی باشد. +stdlib.config.default_which_cache_invalid = ظرفیت پیش‌فرض نهانگاه which باید مثبت باشد. +stdlib.config.workspace_root_absolute = مسیر ریشهٔ فضای کاری باید مطلق باشد. +stdlib.config.fetch_response_limit_positive = کران پاسخ fetch باید مثبت باشد. +stdlib.config.command_output_limit_positive = کران ضبط خروجی فرمان‌ها باید مثبت باشد. +stdlib.config.command_stream_limit_positive = کران جریان فرمان‌ها باید مثبت باشد. +stdlib.config.which_cache_capacity_positive = ظرفیت نهانگاه which باید مثبت باشد. +stdlib.config.skip_dir_empty = مدخل‌های شاخه‌های نادیده‌گرفته‌شده نباید تهی باشند. +stdlib.config.skip_dir_navigation = مدخل‌های شاخه‌های نادیده‌گرفته‌شده نباید «..» داشته باشند. +stdlib.config.skip_dir_separator = مدخل‌های شاخه‌های نادیده‌گرفته‌شده نباید جداکنندهٔ مسیر داشته باشند. +stdlib.config.fetch_cache_empty = مسیر نهانگاه fetch نباید تهی باشد. +stdlib.config.fetch_cache_not_relative = مسیر نهانگاه fetch باید نسبی باشد، اما { $path } به دست آمد. +stdlib.config.fetch_cache_escapes = مسیر نهانگاه fetch نباید از فضای کاری بیرون رود: { $path }. +stdlib.config.open_workspace_root = گشودن شاخهٔ کنونی به‌عنوان ریشهٔ فضای کاری stdlib ممکن نشد. +stdlib.config.resolve_cwd = تعیین شاخهٔ کنونی به‌عنوان ریشهٔ فضای کاری stdlib ممکن نشد. +stdlib.config.cwd_non_utf8 = شاخهٔ کنونی بخش‌هایی دارد که UTF-8 نیستند: { $path }. + +# تشخیص‌های یاور fetch. +stdlib.fetch.url_invalid = نشانی URL نامعتبر «{ $url }»: { $details }. +stdlib.fetch.disallowed = نشانی URL «{ $url }» مجاز نیست: { $details }. +stdlib.fetch.failed = گرفتن «{ $url }» ممکن نشد: { $details }. +stdlib.fetch.cache_read_failed = خواندن مدخل نهانگاه «{ $name }» ممکن نشد: { $details }. +stdlib.fetch.cache_open_failed = گشودن مدخل نهانگاه «{ $name }» ممکن نشد: { $details }. +stdlib.fetch.response_read_failed = خواندن پاسخ از «{ $url }» ممکن نشد: { $details }. +stdlib.fetch.response_buffer_overflow = سرریز میان‌گیر هنگام خواندن «{ $url }». +stdlib.fetch.cache_write_failed = نوشتن نهانگاه برای «{ $url }» ممکن نشد: { $details }. +stdlib.fetch.response_limit_exceeded = پاسخ «{ $url }» از کران { $limit } بایت فراتر رفت. +stdlib.fetch.cache_limit_exceeded = پاسخ نهان‌شدهٔ «{ $name }» از کران { $limit } بایت فراتر رفت. +stdlib.fetch.io_failed = کنش «{ $action }» برای { $path } ناکام ماند: { $details }. +stdlib.fetch.action.sync_cache = همگام‌سازی نهانگاه fetch +stdlib.fetch.action.create_cache_dir = ساخت شاخهٔ نهانگاه fetch +stdlib.fetch.action.open_cache_dir = گشودن شاخهٔ نهانگاه fetch +stdlib.fetch.action.stat_cache = خواندن مشخصات مدخل نهانگاه fetch +stdlib.fetch.action.open_cache_entry = گشودن مدخل نهانگاه fetch + +# تشخیص‌های یاور فرمان‌ها. +stdlib.command.location = فرمان «{ $command }» در قالب «{ $template }» +stdlib.command.spawn_failed = راه‌اندازی { $location } ممکن نشد: { $details }. +stdlib.command.io_failed = ‏{ $location } ناکام ماند: { $details }. +stdlib.command.closed_input_early = ورودی پیش از پایان نوشتن به فرمان بسته شد. +stdlib.command.broken_pipe = گسست لوله هنگام اجرای { $location }: { $details }. +stdlib.command.terminated_by_signal = ‏{ $location } با یک سیگنال پایان یافت. +stdlib.command.exited_with_status = ‏{ $location } با وضعیت { $status } پایان یافت. +stdlib.command.output_limit_exceeded = ‏{ $location } از کران { $mode } برابر { $limit } بایت برای { $stream } فراتر رفت. +stdlib.command.timeout = ‏{ $location } از مهلت { $seconds } ثانیه فراتر رفت. +stdlib.command.exit_status_suffix = ‏(وضعیت خروج { $status }) +stdlib.command.signal_suffix = ‏(با سیگنال پایان یافت) +stdlib.command.shell.empty = فرمان پوسته نباید تهی باشد. +stdlib.command.grep.empty_pattern = الگوی grep نباید تهی باشد. +stdlib.command.grep.flags_not_string = پرچم‌های grep باید رشته باشند. +stdlib.command.quote.invalid = نهادن { $arg } میان گیومه ممکن نشد: { $details }. +stdlib.command.quote.line_break = آرگومان‌هایی که بازگشت به ابتدای خط یا شکست سطر دارند به‌شکل ایمن میان گیومه نمی‌گنجند. +stdlib.command.input_undefined = مقدار ورودی تعریف نشده است. +stdlib.command.tempfile.root_required = ساخت پرونده‌های موقت فرمان به ریشهٔ فضای کاری نیاز دارد. +stdlib.command.tempfile.create_failed = ساخت پروندهٔ موقت فرمان ممکن نشد: { $details }. +stdlib.command.options.invalid_utf8 = کلید گزینهٔ فرمان باید UTF-8 معتبر باشد. +stdlib.command.option.mode_not_string = حالت خروجی باید رشته باشد. +stdlib.command.options.invalid_type = گزینه‌های فرمان باید شیء باشند. +stdlib.command.output.mode_unsupported = حالت خروجی پشتیبانی‌نشده: «{ $mode }». +stdlib.command.output.mode.capture = ضبط +stdlib.command.output.mode.streaming = جریان +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# تشخیص‌های یاور مسیرها. +stdlib.path.io.failed = کنش «{ $action }» برای { $path } ناکام ماند ({ $label }). +stdlib.path.io.failed_with_detail = کنش «{ $action }» برای { $path } ناکام ماند: { $detail }. +stdlib.path.io.failed_with_label_and_detail = کنش «{ $action }» برای { $path } ناکام ماند ({ $label }): { $detail }. +stdlib.path.io.not_found = یافت نشد +stdlib.path.io.permission_denied = دسترسی رد شد +stdlib.path.io.already_exists = از پیش هست +stdlib.path.io.invalid_input = ورودی نامعتبر +stdlib.path.io.invalid_data = دادهٔ نامعتبر +stdlib.path.io.timed_out = مهلت به سر رسید +stdlib.path.io.interrupted = گسسته شد +stdlib.path.io.would_block = سبب انسداد می‌شد +stdlib.path.io.write_zero = صفر بایت نوشته شد +stdlib.path.io.unexpected_eof = پایان نابه‌هنگام پرونده +stdlib.path.io.broken_pipe = گسست لوله +stdlib.path.io.connection_refused = اتصال رد شد +stdlib.path.io.connection_reset = اتصال بازنشانی شد +stdlib.path.io.connection_aborted = اتصال لغو شد +stdlib.path.io.not_connected = بدون اتصال +stdlib.path.io.addr_in_use = نشانی در حال استفاده است +stdlib.path.io.addr_not_available = نشانی در دسترس نیست +stdlib.path.io.out_of_memory = حافظه به پایان رسید +stdlib.path.io.unsupported = پشتیبانی نمی‌شود +stdlib.path.io.file_too_large = پرونده بسیار بزرگ است +stdlib.path.io.resource_busy = منبع مشغول است +stdlib.path.io.executable_busy = پروندهٔ اجرایی مشغول است +stdlib.path.io.deadlock = بن‌بست +stdlib.path.io.crosses_devices = از مرز دستگاه‌ها می‌گذرد +stdlib.path.io.too_many_links = پیوندهای بیش از اندازه +stdlib.path.io.invalid_filename = نام پروندهٔ نامعتبر +stdlib.path.io.arg_list_too_long = فهرست آرگومان‌ها بیش از اندازه بلند است +stdlib.path.io.stale_handle = دستگیرهٔ پروندهٔ شبکه‌ای کهنه +stdlib.path.io.storage_full = فضای ذخیره‌سازی پر است +stdlib.path.io.not_seekable = جای‌گذاری در آن ممکن نیست +stdlib.path.io.network_down = شبکه از کار افتاده است +stdlib.path.io.network_unreachable = شبکه دسترس‌پذیر نیست +stdlib.path.io.host_unreachable = میزبان دسترس‌پذیر نیست +stdlib.path.io.other = خطای ورودی/خروجی +stdlib.path.action.canonicalize = متعارف‌سازی +stdlib.path.action.open_directory = گشودن شاخه +stdlib.path.action.stat = خواندن مشخصات +stdlib.path.action.read = خواندن +stdlib.path.action.open_file = گشودن پرونده +stdlib.path.with_suffix.empty_separator = ‏with_suffix به جداکننده‌ای ناتهی نیاز دارد. +stdlib.path.relative_to.mismatch = ‏{ $path } نسبت به { $root } نسبی نیست. +stdlib.path.expanduser.unsupported = گسترش ~ برای کاربری معین پشتیبانی نمی‌شود. +stdlib.path.expanduser.no_home = گسترش ~ ممکن نیست: هیچ متغیر محیطی برای شاخهٔ خانگی تنظیم نشده است. +stdlib.path.contents.unsupported_encoding = رمزگذاری پشتیبانی‌نشده: «{ $encoding }». +stdlib.path.hash.unsupported_algorithm = الگوریتم درهم‌سازی پشتیبانی‌نشده: «{ $algorithm }». +stdlib.path.hash.unsupported_algorithm_legacy = الگوریتم درهم‌سازی پشتیبانی‌نشده: «{ $algorithm }» (ویژگی «{ $feature }» را فعال کنید). + +# تشخیص‌های یاورهای گردایه‌ها. +stdlib.collections.flatten.expected_sequence = ‏flatten عضوهای یک دنباله را انتظار داشت اما { $kind } یافت. +stdlib.collections.group_by.empty_attribute = ‏group_by به ویژگی‌ای ناتهی نیاز دارد. +stdlib.collections.group_by.unresolved = ‏group_by نتوانست «{ $attr }» را روی عضوی از گونهٔ { $kind } بیابد. + +# تشخیص‌های یاورهای زمان. +stdlib.time.offset.invalid = اختلاف زمانی now «{ $offset }» نامعتبر است: «+HH:MM[:SS]» یا «Z» انتظار می‌رفت. +stdlib.time.timedelta.overflow = سرریز timedelta هنگام افزودن { $component }. +stdlib.time.label.weeks = هفته +stdlib.time.label.days = روز +stdlib.time.label.hours = ساعت +stdlib.time.label.minutes = دقیقه +stdlib.time.label.seconds = ثانیه +stdlib.time.label.milliseconds = میلی‌ثانیه +stdlib.time.label.microseconds = میکروثانیه +stdlib.time.label.nanoseconds = نانوثانیه + +# تشخیص‌های یاور which. +stdlib.which.not_found = ‏[netsuke::jinja::which::not_found] فرمان «{ $command }» پس از بررسی { $count } مدخل PATH یافت نشد. پیش‌نمایش: { $preview } +stdlib.which.not_found.hint.cwd_auto = بخش‌های تهی PATH نادیده گرفته می‌شوند؛ برای دربرگرفتن شاخهٔ کاری از cwd_mode="auto" استفاده کنید. +stdlib.which.not_found.hint.cwd_always = برای دربرگرفتن شاخهٔ کنونی، cwd_mode="always" را تنظیم کنید. +stdlib.which.direct_not_found = ‏[netsuke::jinja::which::not_found] فرمان «{ $command }» در «{ $path }» وجود ندارد یا اجراشدنی نیست. +stdlib.which.args_error = ‏[netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = ‏<تهی> +stdlib.which.path_entry.non_utf8 = مدخل شمارهٔ { $index } در PATH نویسه‌هایی دارد که UTF-8 نیستند؛ ‏Netsuke به مسیرهای UTF-8 نیاز دارد. +stdlib.which.command.empty = ‏which به رشته‌ای ناتهی نیاز دارد. +stdlib.which.cwd_mode.invalid = ‏cwd_mode باید «auto»، «always» یا «never» باشد، اما «{ $mode }» به دست آمد. +stdlib.which.cwd.resolve_failed = تعیین شاخهٔ کنونی ممکن نشد: { $details }. +stdlib.which.cwd.non_utf8 = شاخهٔ کنونی بخش‌هایی دارد که UTF-8 نیستند. +stdlib.which.canonicalize_failed = متعارف‌سازی «{ $path }» ممکن نشد: { $details }. +stdlib.which.is_executable = بررسی اجراشدنی‌بودن «{ $path }» ممکن نشد: { $details }. +stdlib.which.canonicalize_non_utf8 = مسیر متعارف بخش‌هایی دارد که UTF-8 نیستند. +stdlib.which.workspace_non_utf8 = مسیر فضای کاری هنگام یافتن فرمان «{ $command }» بخش‌هایی دارد که UTF-8 نیستند: { $path }. +stdlib.which.walkdir_error = خطا هنگام پیمایش فضای کاری برای یافتن فرمان: { $details }. + +# ثبت کتابخانهٔ استاندارد. +stdlib.register.open_dir = گشودن شاخهٔ کنونی برای ثبت stdlib ممکن نشد. +stdlib.register.resolve_dir = تعیین شاخهٔ کنونی برای ثبت stdlib ممکن نشد. +stdlib.register.dir_non_utf8 = شاخهٔ کنونی بخش‌هایی دارد که UTF-8 نیستند: { $path }. + +# گزارش وضعیت برای حالت خروجی دسترس‌پذیر. +status.state.pending = در انتظار +status.state.running = در جریان +status.state.done = انجام شد +status.state.failed = ناکام +status.stage.label = مرحلهٔ { $current }/{ $total }: { $description } +status.stage.summary = ‏[{ $state }] { $label } +status.stage.summary_with_task = ‏[{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = کار { $current }/{ $total } +status.task.progress_update = ‏{ $task }: { $description } +status.stage.manifest_ingestion = خواندن پروندهٔ مانیفست +status.stage.initial_yaml_parsing = تجزیهٔ سند YAML +status.stage.template_expansion = گسترش دستورهای قالب +status.stage.final_rendering = بازگرداندن و نمایش مقادیر مانیفست +status.stage.ir_generation_validation = ساخت و بررسی گراف وابستگی‌ها +status.stage.ninja_synthesis = ترکیب طرح ساخت Ninja +status.stage.ninja_synthesis_execute = ترکیب طرح Ninja و اجرای { $tool } +status.stage.graph_rendering = نمایش فرآوردهٔ گراف +status.stage.graph_rendering_with_tool = نمایش { $tool } +status.complete = ‏{ $tool } به پایان رسید. +status.timing.summary_header = خلاصهٔ زمان به تفکیک مرحله: +status.timing.stage_line = ‏- { $label }: { $duration } +status.timing.total_line = زمان کل خط پردازش: { $duration } +status.tool.build = ساخت +status.tool.clean = پاک‌سازی +status.tool.graph = گراف +status.tool.graph_html = گراف (HTML) +status.tool.generate = تولید + +# رشته‌های نمایش گراف به شکل HTML. +graph.html.title = گراف ساخت Netsuke +graph.html.heading = گراف ساخت Netsuke +graph.html.description = گراف ساختی که Netsuke نمایش داده است +graph.html.outline.summary = هدف‌ها و وابستگی‌ها (طرح متنی) +graph.html.outline.no_inputs = بدون ورودی +graph.html.noscript.notice = ‏JavaScript از کار افتاده است. طرح متنی بالا همان گراف کامل است؛ کد DOT در پی می‌آید. + +# پیشوندهای معنایی برای خروجی دسترس‌پذیر. +semantic.prefix.error = خطا: +semantic.prefix.warning = هشدار: +semantic.prefix.success = موفق: +semantic.prefix.info = آگاهی: +semantic.prefix.timing = زمان: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# نمونه‌های صورت جمع برای مترجمان. +# فارسی در CLDR دو ردهٔ `one` و `other` دارد، ولی اسم پس از عدد مفرد می‌ماند. +example.files_processed = { $count -> + [one] ‏{ $count } پرونده پردازش شد. + *[other] ‏{ $count } پرونده پردازش شد. +} + +example.errors_found = { $count -> + [0] هیچ خطایی یافت نشد. + [one] ‏{ $count } خطا یافت شد. + *[other] ‏{ $count } خطا یافت شد. +} diff --git a/locales/fi/messages.ftl b/locales/fi/messages.ftl new file mode 100644 index 000000000..8a043befe --- /dev/null +++ b/locales/fi/messages.ftl @@ -0,0 +1,399 @@ +# Netsuken komentorivin lokalisointiresurssit. + +cli.about = Netsuke kääntää YAML- ja Jinja-manifestit Ninja-koontisuunnitelmiksi. +cli.long_about = Netsuke muuntaa YAML- ja Jinja-manifestit toistettaviksi Ninja-graafeiksi ja suorittaa Ninjan turvallisin oletusasetuksin. +cli.usage = { $usage } + +# Yleisten valitsimien ohjeteksti. +cli.flag.file.help = Käytettävän Netsuke-manifestitiedoston polku. +cli.flag.directory.help = Suorita ikään kuin ohjelma olisi käynnistetty tässä hakemistossa. +cli.flag.config.help = Asetustiedoston polku, joka ohittaa automaattisen haun. +cli.flag.jobs.help = Aseta rinnakkaisten koontitöiden määrä. +cli.flag.verbose.help = Ota käyttöön yksityiskohtainen diagnostiikkaloki ja ajoituskoosteet lopuksi. +cli.flag.locale.help = Komentorivin tekstien kielitunnus (esimerkiksi: en-US, fi). +cli.flag.fetch_allow_scheme.help = Lisää URL-skeemoja, jotka fetch-apuri saa käyttää. +cli.flag.fetch_allow_host.help = Sallitut isäntänimet, kun oletusesto on käytössä. +cli.flag.fetch_block_host.help = Isäntänimet, jotka estetään aina, vaikka ne sallittaisiin muualla. +cli.flag.fetch_default_deny.help = Estä kaikki isännät oletuksena; salli vain määritelty luettelo. +cli.flag.json.help = Tuota koneluettavaa JSON-tulostetta. +cli.flag.no_input.help = Älä koskaan lue vuorovaikutteista syötettä. +cli.flag.color.help = Väritulosteen käytäntö (auto, always, never). +cli.flag.emoji.help = Emojien käytäntö (auto, always, never). +cli.flag.progress.help = Edistymisen näyttämisen käytäntö (auto, always, never). +cli.flag.accessibility.help = Saavutettavan tulosteen käytäntö (auto, on, off). +cli.flag.default_targets.help = Koonnin oletuskohteet, kun mitään ei ole annettu. + +# Alikomentojen kuvaukset. +cli.subcommand.build.about = Koosta manifestissa määritellyt kohteet (oletus). +cli.subcommand.build.long_about = Koosta pyydetyt kohteet; jos niitä ei anneta, käytä manifestin oletuskohteita. +cli.subcommand.clean.about = Poista koonnin tuotokset Ninjan avulla. +cli.subcommand.clean.long_about = Luo väliaikainen Ninja-tiedosto ja suorita sitten `ninja -t clean`. +cli.subcommand.graph.about = Tulosta koonnin riippuvuusgraafi. Oletusmuoto on DOT. +cli.subcommand.graph.long_about = Muunna luettu Netsuke-manifesti kanoniseksi koontigraafiksi ja kirjoita se Graphviz DOT -muodossa tai `--html`-valitsimella itsenäisenä HTML-sivuna. Kirjoita tiedostoon valitsimella `--output `; `-` kirjoittaa vakiotulosteeseen. +cli.subcommand.generate.about = Luo Ninja-manifesti suorittamatta Ninjaa. +cli.subcommand.generate.long_about = Kirjoita luotu Ninja-manifesti vakiotulosteeseen tai valitsimella `--output` valittuun tiedostoon. + +# build-alikomennon valitsimien ohjeteksti. +cli.subcommand.build.flag.targets.help = Koostettavat kohteet (jos puuttuu, käytetään manifestin oletuskohteita). + +# graph-alikomennon valitsimien ohjeteksti. +cli.subcommand.graph.flag.html.help = Hahmonna graafi itsenäisenä HTML-sivuna DOT-muodon sijaan. +cli.subcommand.graph.flag.output.help = Kirjoita graafituotos TIEDOSTOon; käytä `-` vakiotulosteeseen. + +# generate-alikomennon valitsimien ohjeteksti. +cli.subcommand.generate.flag.output.help = Kirjoita luotu Ninja-manifesti TIEDOSTOon vakiotulosteen sijaan. + +# Komentorivin kelpoisuustarkistusten virheet. +cli.validation.jobs.invalid_number = { $value } ei ole kelvollinen luku. +cli.validation.jobs.out_of_range = Töiden määrän on oltava välillä { $min }–{ $max }. +cli.validation.scheme.empty = Skeema ei saa olla tyhjä. +cli.validation.scheme.invalid_start = Skeeman ”{ $scheme }” on alettava ASCII-kirjaimella. +cli.validation.scheme.invalid = Virheellinen skeema ”{ $scheme }”. +cli.validation.locale.empty = Kielitunnus ei saa olla tyhjä. +cli.validation.locale.invalid = Virheellinen kielitunnus ”{ $locale }”. +cli.validation.color.invalid = Virheellinen värikäytäntö ”{ $value }”. Kelvolliset vaihtoehdot: auto, always, never. +cli.validation.emoji.invalid = Virheellinen emojikäytäntö ”{ $value }”. Kelvolliset vaihtoehdot: auto, always, never. +cli.validation.progress.invalid = Virheellinen edistymiskäytäntö ”{ $value }”. Kelvolliset vaihtoehdot: auto, always, never. +cli.validation.accessibility.invalid = Virheellinen saavutettavuuskäytäntö ”{ $value }”. Kelvolliset vaihtoehdot: auto, on, off. +cli.validation.config.expected_object = Komentorivin arvojen piti sarjallistua objektiksi, mutta saatiin { $value }. + +# Clapin virheilmoitukset. +clap-error-missing-argument = Pakollinen argumentti puuttuu: { $argument } +clap-error-missing-subcommand = Alikomento puuttuu. Käytettävissä olevat vaihtoehdot: { $valid_subcommands } +clap-error-unknown-argument = Tuntematon argumentti: { $argument } +clap-error-invalid-value = Virheellinen arvo argumentille { $argument }: { $value } +clap-error-invalid-subcommand = Tuntematon alikomento: { $subcommand } +# Huomio: value-validation on muotoiltu eri tavalla kuin invalid-value, jotta +# omien tarkistimien virheet (ErrorKind::ValueValidation) erottuvat +# tyyppiristiriidoista (ErrorKind::InvalidValue). +clap-error-value-validation = Kelpoisuustarkistus epäonnistui argumentille { $argument }: { $value } + +# Suorittajan virheet ja konteksti. +runner.manifest.not_found = Manifestia ”{ $manifest_name }” ei löytynyt hakemistosta { $directory }. +runner.manifest.not_found.help = Varmista, että manifesti on olemassa, tai anna `--file` oikealla polulla. +runner.manifest.path_missing_name = Manifestipolussa ”{ $path }” ei ole tiedostonimeä. +runner.manifest.path_utf8 = Manifestipolku ”{ $path }” ei ole kelvollista UTF-8:aa. +runner.manifest.directory_utf8 = Manifestihakemiston polku ”{ $path }” ei ole kelvollista UTF-8:aa. +runner.manifest.directory_label = hakemisto `{ $directory }` +runner.manifest.current_directory_label = nykyinen hakemisto +runner.context.network_policy = Verkkokäytäntöä ei voitu muodostaa. +runner.context.load_manifest = Manifestia ei voitu ladata polusta { $path }. +runner.context.serialise_manifest = Manifestia ei voitu sarjallistaa. +runner.context.build_graph = Graafia ei voitu muodostaa manifestista. +runner.context.generate_ninja = Ninja-manifestia ei voitu luoda. +runner.context.render_graph = Graafituotosta ei voitu hahmontaa. + +runner.io.create_temp_file = Väliaikaista Ninja-tiedostoa ei voitu luoda. +runner.io.write_temp_ninja = Väliaikaista Ninja-tiedostoa ei voitu kirjoittaa. +runner.io.flush_temp_ninja = Väliaikaisen Ninja-tiedoston puskuria ei voitu tyhjentää. +runner.io.sync_temp_ninja = Väliaikaista Ninja-tiedostoa ei voitu synkronoida. +runner.io.create_parent_dir = Ylähakemistoa { $path } ei voitu luoda. +runner.io.create_ninja_file = Ninja-tiedostoa polkuun { $path } ei voitu luoda. +runner.io.write_ninja_file = Ninja-tiedostoa polussa { $path } ei voitu kirjoittaa. +runner.io.flush_ninja_file = Ninja-tiedoston puskuria polussa { $path } ei voitu tyhjentää. +runner.io.sync_ninja_file = Ninja-tiedostoa polussa { $path } ei voitu synkronoida. +runner.io.open_ambient_dir = Ympäröivää hakemistoa ei voitu avata. +runner.io.no_existing_ancestor = Polulle { $path } ei löydy olemassa olevaa ylähakemistoa. +runner.io.derive_relative_path = Suhteellista Ninja-polkua ei voitu johtaa. +runner.io.non_utf8_path = Polkuja, jotka eivät ole UTF-8:aa, ei tueta (polku: { $path }). +runner.io.write_stdout = Ninja-manifestia ei voitu kirjoittaa vakiotulosteeseen. +runner.io.flush_stdout = Vakiotulosteen puskuria ei voitu tyhjentää. + +# Manifestin diagnostiikka. +manifest.parse = Manifestin jäsentäminen epäonnistui. +manifest.structure_error = Manifestin rakennevirhe kohdassa { $name }: { $details } +manifest.yaml.parse = YAML-jäsennysvirhe rivillä { $line }, sarakkeessa { $column }: { $details } +manifest.yaml.label = virheellinen YAML +manifest.yaml.hint.tabs = YAML ei salli sarkaimia; käytä sisennykseen välilyöntejä. +manifest.yaml.hint.list_item = YAML-luettelon alkioiden on alettava merkillä ”-” ja oltava oikein sisennettyjä. +manifest.yaml.hint.expected_colon = Tämä näyttää avain-arvo-parilta; avaimen jälkeen puuttuu ”:”. +manifest.yaml.hint.mapping_values = YAML-kuvaukset vaativat arvon merkin ”:” jälkeen (tai sisennetyn lohkon). +manifest.yaml.hint.invalid_token = YAML-tunnus on virheellinen tai odottamaton. +manifest.yaml.hint.escape = Suojaa kenoviivat tai poista virheelliset ohjausmerkkijonot. +manifest.env.missing = Vaadittua ympäristömuuttujaa ”{ $name }” ei ole asetettu. +manifest.env.invalid_utf8 = Ympäristömuuttuja ”{ $name }” sisältää virheellistä UTF-8:aa. +manifest.vars.not_object = Manifestin `vars` on oltava kuvaus tai objekti. +manifest.read_failed = Manifestia ei voitu lukea polusta { $path }. +manifest.resolve_workspace_root = Työtilan juurta ei voitu selvittää. +manifest.workspace_non_utf8 = Työtilan juuripolku ”{ $path }” ei ole kelvollista UTF-8:aa. +manifest.path_non_utf8 = Manifestin ”{ $manifest }” polku ei ole kelvollista UTF-8:aa: { $path }. +manifest.path_missing_name = Manifestipolussa ”{ $path }” ei ole tiedostonimeä. +manifest.open_workspace_failed = Työtilaa { $workspace } ei voitu avata manifestille { $manifest }. +manifest.foreach.not_iterable = Lauseke `foreach` ei ole läpikäytävissä. +manifest.foreach.serialise_item = Lausekkeen `foreach` alkiota ei voitu sarjallistaa. +manifest.when.empty = Lauseke `when` ei saa olla tyhjä. +manifest.when.eval_error = Lauseketta `when` ”{ $expr }” ei voitu evaluoida. +manifest.when.template_error = Mallipohjaa `when` ”{ $expr }” ei voitu hahmontaa. +manifest.target.vars_not_object = Kohteen `vars` on oltava objekti, mutta saatiin { $value }. +manifest.vars.entry_not_object = Manifestin `vars`-merkinnän on oltava objekti. +manifest.field_not_string = Kentän ”{ $field }” on oltava merkkijono. +manifest.expression.parse_error = Lauseketta { $name } ei voitu jäsentää. +manifest.expression.eval_error = Lauseketta { $name } ei voitu evaluoida. + +# Manifestin makrojen diagnostiikka. +manifest.macro.signature_missing_identifier = Makron esittelystä puuttuu tunniste. +manifest.macro.signature_missing_params = Makron esittelystä puuttuvat parametrit. +manifest.macro.compile_failed = Makroa { $name } ei voitu kääntää. +manifest.macro.sequence_invalid = Makrot on määriteltävä nimien ja mallipohjien kuvauksena. +manifest.macro.register_failed = Manifestin makroja ei voitu rekisteröidä. +manifest.macro.not_initialised = Makroympäristöä ei ole alustettu. +manifest.macro.caller_invalid = Makron kutsujan on oltava merkkijono. +manifest.macro.template_load_failed = Makron mallipohjaa ei voitu ladata. +manifest.macro.init_failed = Makroympäristöä ei voitu alustaa. +manifest.macro.missing = Makro { $name } puuttuu. + +# Manifestin glob-virheet. +manifest.glob.unmatched_brace = Virheellinen glob-hahmo ”{ $pattern }”: merkillä ”{ $character }” ei ole paria kohdassa { $position }. +manifest.glob.invalid_pattern = Virheellinen glob-hahmo ”{ $pattern }”: { $detail }. +manifest.glob.unknown_pattern_error = tuntematon hahmovirhe. +manifest.glob.io_failed = Glob epäonnistui hahmolle ”{ $pattern }”: { $detail }. +manifest.glob.unknown_io_error = tuntematon siirräntävirhe. + +# Välimuotoesityksen virheet. +ir.rule_not_found = Sääntöä ”{ $rule }”, johon kohde ”{ $target }” viittaa, ei löytynyt. +ir.multiple_rules = Kohteen ”{ $target }” on viitattava täsmälleen yhteen sääntöön, mutta saatiin { $rules }. +ir.empty_rule = Kohteen ”{ $target }” on viitattava sääntöön. +ir.duplicate_outputs = Havaittiin päällekkäisiä tulosteita: { $outputs }. +ir.circular_dependency = Havaittiin kehäriippuvuus: { $cycle }. +ir.action_serialisation = Toimintoa ei voitu sarjallistaa: { $details }. +ir.invalid_command = Virheellinen komennon sijoitus: { $snippet }. + +# Ninja-generoinnin virheet. +ninja_gen.missing_action = Toiminto ”{ $id }”, johon koontikaari viittaa, puuttuu. +ninja_gen.format = Ninja-manifestin tulostetta ei voitu muotoilla. + +# Isäntähahmojen tarkistus. +host_pattern.empty = Isäntähahmo ei saa olla tyhjä. +host_pattern.contains_scheme = Isäntähahmo ”{ $pattern }” ei saa sisältää URL-skeemaa. +host_pattern.contains_slash = Isäntähahmo ”{ $pattern }” ei saa sisältää merkkiä ”/”. +host_pattern.missing_suffix = Isäntähahmossa ”{ $pattern }” on oltava pääte merkkijonon ”*.” jälkeen. +host_pattern.empty_label = Isäntähahmo ”{ $pattern }” sisältää tyhjän nimiön. +host_pattern.invalid_chars = Isäntähahmo ”{ $pattern }” sisältää virheellisiä merkkejä. +host_pattern.invalid_label_edge = Isäntähahmon ”{ $pattern }” nimiöt eivät saa alkaa tai päättyä merkkiin ”-”. +host_pattern.label_too_long = Isäntähahmo ”{ $pattern }” sisältää yli 63 merkin nimiön. +host_pattern.too_long = Isäntähahmo ”{ $pattern }” ylittää 255 merkin rajan. + +# Verkkokäytäntö. +network_policy.scheme.empty = Skeema ei saa olla tyhjä. +network_policy.scheme.invalid = Skeema ”{ $scheme }” sisältää virheellisiä merkkejä. +network_policy.allowlist.empty = Sallittujen isäntien luettelo ei saa olla tyhjä. +network_policy.scheme.not_allowed = Skeema ”{ $scheme }” ei ole sallittu. +network_policy.missing_host = URL-osoitteesta puuttuu isäntä. +network_policy.host.blocked = Käytäntö estää isännän ”{ $host }”. +network_policy.host.not_allowlisted = Isäntä ”{ $host }” ei ole sallittujen luettelossa. + +# Vakiokirjaston asetukset. +stdlib.config.default_fetch_cache_invalid = fetch-välimuistin oletuspolun on oltava suhteellinen. +stdlib.config.default_which_cache_invalid = which-välimuistin oletuskapasiteetin on oltava positiivinen. +stdlib.config.workspace_root_absolute = Työtilan juuripolun on oltava absoluuttinen. +stdlib.config.fetch_response_limit_positive = fetch-vastauksen rajan on oltava positiivinen. +stdlib.config.command_output_limit_positive = Komennon tulosteen talteenoton rajan on oltava positiivinen. +stdlib.config.command_stream_limit_positive = Komennon virtausrajan on oltava positiivinen. +stdlib.config.which_cache_capacity_positive = which-välimuistin kapasiteetin on oltava positiivinen. +stdlib.config.skip_dir_empty = Ohitettavien hakemistojen merkinnät eivät saa olla tyhjiä. +stdlib.config.skip_dir_navigation = Ohitettavien hakemistojen merkinnät eivät saa sisältää merkkijonoa ”..”. +stdlib.config.skip_dir_separator = Ohitettavien hakemistojen merkinnät eivät saa sisältää polkuerottimia. +stdlib.config.fetch_cache_empty = fetch-välimuistin polku ei saa olla tyhjä. +stdlib.config.fetch_cache_not_relative = fetch-välimuistin polun on oltava suhteellinen, mutta saatiin { $path }. +stdlib.config.fetch_cache_escapes = fetch-välimuistin polku ei saa johtaa työtilan ulkopuolelle: { $path }. +stdlib.config.open_workspace_root = Nykyistä hakemistoa ei voitu avata stdlib-työtilan juureksi. +stdlib.config.resolve_cwd = Nykyistä hakemistoa ei voitu selvittää stdlib-työtilan juureksi. +stdlib.config.cwd_non_utf8 = Nykyinen hakemisto sisältää osia, jotka eivät ole UTF-8:aa: { $path }. + +# fetch-apurin diagnostiikka. +stdlib.fetch.url_invalid = Virheellinen URL-osoite ”{ $url }”: { $details }. +stdlib.fetch.disallowed = URL-osoite ”{ $url }” ei ole sallittu: { $details }. +stdlib.fetch.failed = Osoitteesta ”{ $url }” ei voitu hakea: { $details }. +stdlib.fetch.cache_read_failed = Välimuistimerkintää ”{ $name }” ei voitu lukea: { $details }. +stdlib.fetch.cache_open_failed = Välimuistimerkintää ”{ $name }” ei voitu avata: { $details }. +stdlib.fetch.response_read_failed = Vastausta osoitteesta ”{ $url }” ei voitu lukea: { $details }. +stdlib.fetch.response_buffer_overflow = Puskurin ylivuoto luettaessa osoitetta ”{ $url }”. +stdlib.fetch.cache_write_failed = Välimuistia osoitteelle ”{ $url }” ei voitu kirjoittaa: { $details }. +stdlib.fetch.response_limit_exceeded = Vastaus osoitteesta ”{ $url }” ylitti { $limit } tavun rajan. +stdlib.fetch.cache_limit_exceeded = Välimuistiin tallennettu vastaus ”{ $name }” ylitti { $limit } tavun rajan. +stdlib.fetch.io_failed = { $action } epäonnistui polun { $path } käsittelyssä: { $details }. +stdlib.fetch.action.sync_cache = fetch-välimuistin synkronointi +stdlib.fetch.action.create_cache_dir = fetch-välimuistihakemiston luonti +stdlib.fetch.action.open_cache_dir = fetch-välimuistihakemiston avaus +stdlib.fetch.action.stat_cache = fetch-välimuistimerkinnän haku +stdlib.fetch.action.open_cache_entry = fetch-välimuistimerkinnän avaus + +# Komentoapurin diagnostiikka. +stdlib.command.location = komento ”{ $command }” mallipohjassa ”{ $template }” +stdlib.command.spawn_failed = Kohdetta { $location } ei voitu käynnistää: { $details }. +stdlib.command.io_failed = { $location } epäonnistui: { $details }. +stdlib.command.closed_input_early = Syöte sulkeutui ennen kuin kirjoitus komennolle valmistui. +stdlib.command.broken_pipe = Katkennut putki suoritettaessa kohdetta { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } päättyi signaaliin. +stdlib.command.exited_with_status = { $location } päättyi tilaan { $status }. +stdlib.command.output_limit_exceeded = { $location } ylitti { $mode }-rajan { $limit } tavua virralle { $stream }. +stdlib.command.timeout = { $location } ylitti { $seconds } sekunnin aikarajan. +stdlib.command.exit_status_suffix = (päättymistila { $status }) +stdlib.command.signal_suffix = (päättyi signaaliin) +stdlib.command.shell.empty = Komentotulkin komento ei saa olla tyhjä. +stdlib.command.grep.empty_pattern = grep-hahmo ei saa olla tyhjä. +stdlib.command.grep.flags_not_string = grep-valitsimien on oltava merkkijonoja. +stdlib.command.quote.invalid = Argumenttia { $arg } ei voitu lainausmerkitä: { $details }. +stdlib.command.quote.line_break = Argumentteja, joissa on vaunupalautus tai rivinvaihto, ei voi lainausmerkitä turvallisesti. +stdlib.command.input_undefined = Syötteen arvoa ei ole määritelty. +stdlib.command.tempfile.root_required = Komentojen väliaikaistiedostojen luonti vaatii työtilan juuren. +stdlib.command.tempfile.create_failed = Komennon väliaikaistiedostoa ei voitu luoda: { $details }. +stdlib.command.options.invalid_utf8 = Komennon asetusavaimen on oltava kelvollista UTF-8:aa. +stdlib.command.option.mode_not_string = Tulostetilan on oltava merkkijono. +stdlib.command.options.invalid_type = Komennon asetusten on oltava objekti. +stdlib.command.output.mode_unsupported = Tulostetilaa ”{ $mode }” ei tueta. +stdlib.command.output.mode.capture = talteenotto +stdlib.command.output.mode.streaming = virtaus +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Polkuapurin diagnostiikka. +stdlib.path.io.failed = { $action } epäonnistui polun { $path } käsittelyssä ({ $label }). +stdlib.path.io.failed_with_detail = { $action } epäonnistui polun { $path } käsittelyssä: { $detail }. +stdlib.path.io.failed_with_label_and_detail = { $action } epäonnistui polun { $path } käsittelyssä ({ $label }): { $detail }. +stdlib.path.io.not_found = ei löytynyt +stdlib.path.io.permission_denied = käyttö evätty +stdlib.path.io.already_exists = on jo olemassa +stdlib.path.io.invalid_input = virheellinen syöte +stdlib.path.io.invalid_data = virheelliset tiedot +stdlib.path.io.timed_out = aikakatkaisu +stdlib.path.io.interrupted = keskeytetty +stdlib.path.io.would_block = estäisi suorituksen +stdlib.path.io.write_zero = nolla tavua kirjoitettu +stdlib.path.io.unexpected_eof = odottamaton tiedoston loppu +stdlib.path.io.broken_pipe = katkennut putki +stdlib.path.io.connection_refused = yhteys torjuttiin +stdlib.path.io.connection_reset = yhteys nollattiin +stdlib.path.io.connection_aborted = yhteys keskeytettiin +stdlib.path.io.not_connected = ei yhteyttä +stdlib.path.io.addr_in_use = osoite on käytössä +stdlib.path.io.addr_not_available = osoite ei ole käytettävissä +stdlib.path.io.out_of_memory = muisti loppui +stdlib.path.io.unsupported = ei tuettu +stdlib.path.io.file_too_large = tiedosto on liian suuri +stdlib.path.io.resource_busy = resurssi on varattu +stdlib.path.io.executable_busy = ohjelmatiedosto on varattu +stdlib.path.io.deadlock = lukkiutuma +stdlib.path.io.crosses_devices = ylittää laiterajan +stdlib.path.io.too_many_links = liian monta linkkiä +stdlib.path.io.invalid_filename = virheellinen tiedostonimi +stdlib.path.io.arg_list_too_long = argumenttiluettelo on liian pitkä +stdlib.path.io.stale_handle = vanhentunut verkkotiedostokahva +stdlib.path.io.storage_full = tallennustila on täynnä +stdlib.path.io.not_seekable = ei tue kohdistusta +stdlib.path.io.network_down = verkko on alhaalla +stdlib.path.io.network_unreachable = verkkoa ei tavoiteta +stdlib.path.io.host_unreachable = isäntää ei tavoiteta +stdlib.path.io.other = siirräntävirhe +stdlib.path.action.canonicalize = kanonisointi +stdlib.path.action.open_directory = hakemiston avaus +stdlib.path.action.stat = tietojen haku +stdlib.path.action.read = luku +stdlib.path.action.open_file = tiedoston avaus +stdlib.path.with_suffix.empty_separator = with_suffix vaatii erottimen, joka ei ole tyhjä. +stdlib.path.relative_to.mismatch = { $path } ei ole suhteellinen polkuun { $root } nähden. +stdlib.path.expanduser.unsupported = Käyttäjäkohtaista ~-laajennusta ei tueta. +stdlib.path.expanduser.no_home = Merkkiä ~ ei voi laajentaa: kotihakemiston ympäristömuuttujia ei ole asetettu. +stdlib.path.contents.unsupported_encoding = Merkistökoodausta ”{ $encoding }” ei tueta. +stdlib.path.hash.unsupported_algorithm = Tiivistealgoritmia ”{ $algorithm }” ei tueta. +stdlib.path.hash.unsupported_algorithm_legacy = Tiivistealgoritmia ”{ $algorithm }” ei tueta (ota käyttöön ominaisuus ”{ $feature }”). + +# Kokoelma-apurien diagnostiikka. +stdlib.collections.flatten.expected_sequence = flatten odotti jonon alkioita, mutta löysi { $kind }. +stdlib.collections.group_by.empty_attribute = group_by vaatii määritteen, joka ei ole tyhjä. +stdlib.collections.group_by.unresolved = group_by ei löytänyt määritettä ”{ $attr }” tyypin { $kind } alkiosta. + +# Aika-apurien diagnostiikka. +stdlib.time.offset.invalid = now-siirtymä ”{ $offset }” on virheellinen: odotettiin muotoa ”+HH:MM[:SS]” tai ”Z”. +stdlib.time.timedelta.overflow = timedelta-ylivuoto lisättäessä komponenttia { $component }. +stdlib.time.label.weeks = viikkoa +stdlib.time.label.days = päivää +stdlib.time.label.hours = tuntia +stdlib.time.label.minutes = minuuttia +stdlib.time.label.seconds = sekuntia +stdlib.time.label.milliseconds = millisekuntia +stdlib.time.label.microseconds = mikrosekuntia +stdlib.time.label.nanoseconds = nanosekuntia + +# which-apurin diagnostiikka. +stdlib.which.not_found = [netsuke::jinja::which::not_found] komentoa ”{ $command }” ei löytynyt, kun { $count } PATH-merkintää oli tarkistettu. Esikatselu: { $preview } +stdlib.which.not_found.hint.cwd_auto = PATH-muuttujan tyhjät osat ohitetaan; käytä cwd_mode="auto" sisällyttääksesi työhakemiston. +stdlib.which.not_found.hint.cwd_always = Aseta cwd_mode="always" sisällyttääksesi nykyisen hakemiston. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] komento ”{ $command }” polussa ”{ $path }” puuttuu tai ei ole suoritettava. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = PATH-merkintä nro { $index } sisältää merkkejä, jotka eivät ole UTF-8:aa; Netsuke vaatii UTF-8-polkuja. +stdlib.which.command.empty = which vaatii merkkijonon, joka ei ole tyhjä. +stdlib.which.cwd_mode.invalid = cwd_mode-arvon on oltava ”auto”, ”always” tai ”never”, mutta saatiin ”{ $mode }”. +stdlib.which.cwd.resolve_failed = Nykyistä hakemistoa ei voitu selvittää: { $details }. +stdlib.which.cwd.non_utf8 = Nykyinen hakemisto sisältää osia, jotka eivät ole UTF-8:aa. +stdlib.which.canonicalize_failed = Polkua ”{ $path }” ei voitu kanonisoida: { $details }. +stdlib.which.is_executable = Ei voitu selvittää, onko ”{ $path }” suoritettava: { $details }. +stdlib.which.canonicalize_non_utf8 = Kanoninen polku sisältää osia, jotka eivät ole UTF-8:aa. +stdlib.which.workspace_non_utf8 = Työtilan polku sisältää osia, jotka eivät ole UTF-8:aa, selvitettäessä komentoa ”{ $command }”: { $path }. +stdlib.which.walkdir_error = Virhe työtilan läpikäynnissä komentoa selvitettäessä: { $details }. + +# Vakiokirjaston rekisteröinti. +stdlib.register.open_dir = Nykyistä hakemistoa ei voitu avata stdlib-rekisteröintiä varten. +stdlib.register.resolve_dir = Nykyistä hakemistoa ei voitu selvittää stdlib-rekisteröintiä varten. +stdlib.register.dir_non_utf8 = Nykyinen hakemisto sisältää osia, jotka eivät ole UTF-8:aa: { $path }. + +# Tilaraportointi saavutettavassa tulostetilassa. +status.state.pending = odottaa +status.state.running = käynnissä +status.state.done = valmis +status.state.failed = epäonnistui +status.stage.label = Vaihe { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Tehtävä { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Luetaan manifestitiedostoa +status.stage.initial_yaml_parsing = Jäsennetään YAML-asiakirjaa +status.stage.template_expansion = Laajennetaan mallipohjadirektiivejä +status.stage.final_rendering = Puretaan sarjallistus ja hahmonnetaan manifestin arvot +status.stage.ir_generation_validation = Muodostetaan ja tarkistetaan riippuvuusgraafi +status.stage.ninja_synthesis = Muodostetaan Ninja-koontisuunnitelma +status.stage.ninja_synthesis_execute = Muodostetaan Ninja-suunnitelma ja suoritetaan { $tool } +status.stage.graph_rendering = Hahmonnetaan graafituotosta +status.stage.graph_rendering_with_tool = Hahmonnetaan { $tool } +status.complete = { $tool } valmis. +status.timing.summary_header = Vaiheiden ajoituskooste: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Putken kokonaisaika: { $duration } +status.tool.build = Koonti +status.tool.clean = Siivous +status.tool.graph = Graafi +status.tool.graph_html = Graafi (HTML) +status.tool.generate = Luonti + +# Graafin HTML-hahmonnuksen tekstit. +graph.html.title = Netsuken koontigraafi +graph.html.heading = Netsuken koontigraafi +graph.html.description = Netsuken hahmontama koontigraafi +graph.html.outline.summary = Kohteet ja riippuvuudet (tekstijäsennys) +graph.html.outline.no_inputs = Ei syötteitä +graph.html.noscript.notice = JavaScript on poissa käytöstä. Yllä oleva tekstijäsennys sisältää koko graafin; DOT-lähde seuraa alla. + +# Saavutettavan tulosteen semanttiset etuliitteet. +semantic.prefix.error = Virhe: +semantic.prefix.warning = Varoitus: +semantic.prefix.success = Onnistui: +semantic.prefix.info = Tiedoksi: +semantic.prefix.timing = Ajoitus: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Monikkomuotojen esimerkkejä kääntäjille. +# Suomi käyttää CLDR-luokkia `one` ja `other`. Luokassa `one` substantiivi on +# yksikön nominatiivissa (”1 tiedosto”), luokassa `other` yksikön +# partitiivissa (”5 tiedostoa”). +example.files_processed = { $count -> + [one] Käsiteltiin { $count } tiedosto. + *[other] Käsiteltiin { $count } tiedostoa. +} + +example.errors_found = { $count -> + [0] Virheitä ei löytynyt. + [one] Löytyi { $count } virhe. + *[other] Löytyi { $count } virhettä. +} diff --git a/locales/fr/messages.ftl b/locales/fr/messages.ftl new file mode 100644 index 000000000..b6f5aa579 --- /dev/null +++ b/locales/fr/messages.ftl @@ -0,0 +1,399 @@ +# Ressources de localisation de l'interface en ligne de commande Netsuke. + +cli.about = Netsuke compile des manifestes YAML + Jinja en plans de compilation Ninja. +cli.long_about = Netsuke transforme des manifestes YAML + Jinja en graphes Ninja reproductibles et exécute Ninja avec des valeurs par défaut sûres. +cli.usage = { $usage } + +# Texte d'aide des options globales. +cli.flag.file.help = Chemin du fichier manifeste Netsuke à utiliser. +cli.flag.directory.help = Exécuter comme si le démarrage avait eu lieu dans ce répertoire. +cli.flag.config.help = Chemin d'un fichier de configuration, sans passer par la détection automatique. +cli.flag.jobs.help = Définir le nombre de tâches de compilation en parallèle. +cli.flag.verbose.help = Activer les journaux de diagnostic détaillés et les résumés de durée en fin d'exécution. +cli.flag.locale.help = Étiquette de langue pour les textes de la CLI (par exemple : en-US, fr). +cli.flag.fetch_allow_scheme.help = Schémas d'URL supplémentaires autorisés pour l'assistant fetch. +cli.flag.fetch_allow_host.help = Noms d'hôte autorisés lorsque le refus par défaut est activé. +cli.flag.fetch_block_host.help = Noms d'hôte toujours bloqués, même s'ils sont autorisés par ailleurs. +cli.flag.fetch_default_deny.help = Refuser tous les hôtes par défaut ; n'autoriser que la liste déclarée. +cli.flag.json.help = Produire une sortie JSON exploitable par une machine. +cli.flag.no_input.help = Ne jamais lire d'entrée interactive. +cli.flag.color.help = Politique de couleur en sortie (auto, always, never). +cli.flag.emoji.help = Politique d'émojis (auto, always, never). +cli.flag.progress.help = Politique d'affichage de la progression (auto, always, never). +cli.flag.accessibility.help = Politique de sortie accessible (auto, on, off). +cli.flag.default_targets.help = Cibles de compilation par défaut lorsqu'aucune n'est indiquée. + +# Descriptions des sous-commandes. +cli.subcommand.build.about = Compiler les cibles définies dans le manifeste (par défaut). +cli.subcommand.build.long_about = Compiler les cibles demandées ; à défaut, utiliser celles du manifeste. +cli.subcommand.clean.about = Supprimer les artefacts de compilation via Ninja. +cli.subcommand.clean.long_about = Générer un fichier Ninja temporaire, puis exécuter `ninja -t clean`. +cli.subcommand.graph.about = Émettre le graphe de dépendances de compilation. Le format par défaut est DOT. +cli.subcommand.graph.long_about = Projeter le manifeste Netsuke analysé en un graphe de compilation canonique et l'écrire au format Graphviz DOT, ou en page HTML autonome avec `--html`. Utilisez `--output ` pour écrire dans un fichier ; `-` écrit sur la sortie standard. +cli.subcommand.generate.about = Générer le manifeste Ninja sans exécuter Ninja. +cli.subcommand.generate.long_about = Écrire le manifeste Ninja généré sur la sortie standard, ou dans un fichier choisi avec `--output`. + +# Texte d'aide des options de la sous-commande build. +cli.subcommand.build.flag.targets.help = Cibles à compiler (utilise celles du manifeste si omis). + +# Texte d'aide des options de la sous-commande graph. +cli.subcommand.graph.flag.html.help = Restituer le graphe en page HTML autonome plutôt qu'en DOT. +cli.subcommand.graph.flag.output.help = Écrire l'artefact de graphe dans FICHIER ; utilisez `-` pour la sortie standard. + +# Texte d'aide des options de la sous-commande generate. +cli.subcommand.generate.flag.output.help = Écrire le manifeste Ninja généré dans FICHIER plutôt que sur la sortie standard. + +# Erreurs de validation de la CLI. +cli.validation.jobs.invalid_number = { $value } n'est pas un nombre valide. +cli.validation.jobs.out_of_range = Le nombre de tâches doit être compris entre { $min } et { $max }. +cli.validation.scheme.empty = Le schéma ne doit pas être vide. +cli.validation.scheme.invalid_start = Le schéma « { $scheme } » doit commencer par une lettre ASCII. +cli.validation.scheme.invalid = Schéma non valide « { $scheme } ». +cli.validation.locale.empty = L'étiquette de langue ne doit pas être vide. +cli.validation.locale.invalid = Étiquette de langue non valide « { $locale } ». +cli.validation.color.invalid = Politique de couleur non valide « { $value } ». Options valides : auto, always, never. +cli.validation.emoji.invalid = Politique d'émojis non valide « { $value } ». Options valides : auto, always, never. +cli.validation.progress.invalid = Politique de progression non valide « { $value } ». Options valides : auto, always, never. +cli.validation.accessibility.invalid = Politique d'accessibilité non valide « { $value } ». Options valides : auto, on, off. +cli.validation.config.expected_object = Les valeurs de la CLI devaient être sérialisées en objet, reçu { $value }. + +# Messages d'erreur de Clap. +clap-error-missing-argument = Argument requis manquant : { $argument } +clap-error-missing-subcommand = Sous-commande manquante. Options disponibles : { $valid_subcommands } +clap-error-unknown-argument = Argument inconnu : { $argument } +clap-error-invalid-value = Valeur non valide pour { $argument } : { $value } +clap-error-invalid-subcommand = Sous-commande inconnue : { $subcommand } +# Remarque : value-validation emploie une formulation distincte d'invalid-value +# afin de différencier les échecs de validateurs personnalisés +# (ErrorKind::ValueValidation) des incompatibilités de type +# (ErrorKind::InvalidValue). +clap-error-value-validation = Échec de la validation de { $argument } : { $value } + +# Erreurs et contextes de l'exécuteur. +runner.manifest.not_found = Manifeste « { $manifest_name } » introuvable dans { $directory }. +runner.manifest.not_found.help = Vérifiez que le manifeste existe ou indiquez `--file` avec le bon chemin. +runner.manifest.path_missing_name = Le chemin de manifeste « { $path } » ne comporte pas de nom de fichier. +runner.manifest.path_utf8 = Le chemin de manifeste « { $path } » n'est pas de l'UTF-8 valide. +runner.manifest.directory_utf8 = Le chemin du répertoire de manifeste « { $path } » n'est pas de l'UTF-8 valide. +runner.manifest.directory_label = répertoire `{ $directory }` +runner.manifest.current_directory_label = le répertoire courant +runner.context.network_policy = Impossible de construire la politique réseau. +runner.context.load_manifest = Impossible de charger le manifeste depuis { $path }. +runner.context.serialise_manifest = Impossible de sérialiser le manifeste. +runner.context.build_graph = Impossible de construire le graphe à partir du manifeste. +runner.context.generate_ninja = Impossible de générer le manifeste Ninja. +runner.context.render_graph = Impossible de restituer l'artefact de graphe. + +runner.io.create_temp_file = Impossible de créer le fichier Ninja temporaire. +runner.io.write_temp_ninja = Impossible d'écrire le fichier Ninja temporaire. +runner.io.flush_temp_ninja = Impossible de vider le tampon du fichier Ninja temporaire. +runner.io.sync_temp_ninja = Impossible de synchroniser le fichier Ninja temporaire. +runner.io.create_parent_dir = Impossible de créer le répertoire parent { $path }. +runner.io.create_ninja_file = Impossible de créer le fichier Ninja dans { $path }. +runner.io.write_ninja_file = Impossible d'écrire le fichier Ninja dans { $path }. +runner.io.flush_ninja_file = Impossible de vider le tampon du fichier Ninja dans { $path }. +runner.io.sync_ninja_file = Impossible de synchroniser le fichier Ninja dans { $path }. +runner.io.open_ambient_dir = Impossible d'ouvrir le répertoire ambiant. +runner.io.no_existing_ancestor = Aucun répertoire ancêtre existant pour { $path }. +runner.io.derive_relative_path = Impossible de déduire le chemin Ninja relatif. +runner.io.non_utf8_path = Les chemins non UTF-8 ne sont pas pris en charge (chemin : { $path }). +runner.io.write_stdout = Impossible d'écrire le manifeste Ninja sur la sortie standard. +runner.io.flush_stdout = Impossible de vider le tampon de la sortie standard. + +# Diagnostics du manifeste. +manifest.parse = L'analyse du manifeste a échoué. +manifest.structure_error = Erreur de structure du manifeste dans { $name } : { $details } +manifest.yaml.parse = Erreur d'analyse YAML à la ligne { $line }, colonne { $column } : { $details } +manifest.yaml.label = YAML non valide +manifest.yaml.hint.tabs = YAML n'autorise pas les tabulations ; utilisez des espaces pour l'indentation. +manifest.yaml.hint.list_item = Les éléments de liste YAML doivent commencer par « - » et être correctement indentés. +manifest.yaml.hint.expected_colon = Cela ressemble à une entrée de mappage ; il manque un « : » après la clé. +manifest.yaml.hint.mapping_values = Les mappages YAML exigent une valeur après « : » (ou un bloc imbriqué). +manifest.yaml.hint.invalid_token = Le jeton YAML est non valide ou inattendu. +manifest.yaml.hint.escape = Échappez les barres obliques inverses ou supprimez les séquences d'échappement non valides. +manifest.env.missing = La variable d'environnement requise « { $name } » n'est pas définie. +manifest.env.invalid_utf8 = La variable d'environnement « { $name } » contient de l'UTF-8 non valide. +manifest.vars.not_object = `vars` du manifeste doit être une table ou un objet. +manifest.read_failed = Impossible de lire le manifeste depuis { $path }. +manifest.resolve_workspace_root = Impossible de résoudre la racine de l'espace de travail. +manifest.workspace_non_utf8 = Le chemin racine de l'espace de travail « { $path } » n'est pas de l'UTF-8 valide. +manifest.path_non_utf8 = Le chemin du manifeste « { $manifest } » n'est pas de l'UTF-8 valide : { $path }. +manifest.path_missing_name = Le chemin de manifeste « { $path } » ne comporte pas de nom de fichier. +manifest.open_workspace_failed = Impossible d'ouvrir l'espace de travail { $workspace } pour le manifeste { $manifest }. +manifest.foreach.not_iterable = L'expression `foreach` n'est pas itérable. +manifest.foreach.serialise_item = Impossible de sérialiser l'élément de `foreach`. +manifest.when.empty = L'expression `when` ne doit pas être vide. +manifest.when.eval_error = Impossible d'évaluer l'expression `when` « { $expr } ». +manifest.when.template_error = Impossible de restituer le gabarit `when` « { $expr } ». +manifest.target.vars_not_object = `vars` de la cible doit être un objet, reçu { $value }. +manifest.vars.entry_not_object = Une entrée `vars` du manifeste doit être un objet. +manifest.field_not_string = Le champ « { $field } » doit être une chaîne. +manifest.expression.parse_error = Impossible d'analyser l'expression { $name }. +manifest.expression.eval_error = Impossible d'évaluer l'expression { $name }. + +# Diagnostics des macros du manifeste. +manifest.macro.signature_missing_identifier = La signature de la macro ne comporte pas d'identifiant. +manifest.macro.signature_missing_params = La signature de la macro ne comporte pas de paramètres. +manifest.macro.compile_failed = Impossible de compiler la macro { $name }. +manifest.macro.sequence_invalid = Les macros doivent être définies comme un mappage de noms vers des gabarits. +manifest.macro.register_failed = Impossible d'enregistrer les macros du manifeste. +manifest.macro.not_initialised = L'environnement de macros n'est pas initialisé. +manifest.macro.caller_invalid = L'appelant de la macro doit être une chaîne. +manifest.macro.template_load_failed = Impossible de charger le gabarit de macro. +manifest.macro.init_failed = Impossible d'initialiser l'environnement de macros. +manifest.macro.missing = La macro { $name } est absente. + +# Erreurs de motifs glob du manifeste. +manifest.glob.unmatched_brace = Motif glob non valide « { $pattern } » : « { $character } » non apparié à la position { $position }. +manifest.glob.invalid_pattern = Motif glob non valide « { $pattern } » : { $detail }. +manifest.glob.unknown_pattern_error = erreur de motif inconnue. +manifest.glob.io_failed = Échec du glob pour « { $pattern } » : { $detail }. +manifest.glob.unknown_io_error = erreur d'E/S inconnue. + +# Erreurs de la représentation intermédiaire. +ir.rule_not_found = La règle « { $rule } » référencée par la cible « { $target } » est introuvable. +ir.multiple_rules = La cible « { $target } » doit référencer une seule règle, reçu { $rules }. +ir.empty_rule = La cible « { $target } » doit référencer une règle. +ir.duplicate_outputs = Sorties en double détectées : { $outputs }. +ir.circular_dependency = Dépendance circulaire détectée : { $cycle }. +ir.action_serialisation = Impossible de sérialiser l'action : { $details }. +ir.invalid_command = Interpolation de commande non valide : { $snippet }. + +# Erreurs de génération Ninja. +ninja_gen.missing_action = Action « { $id } » manquante alors qu'une arête de compilation la référence. +ninja_gen.format = Impossible de formater la sortie du manifeste Ninja. + +# Validation des motifs d'hôte. +host_pattern.empty = Le motif d'hôte ne doit pas être vide. +host_pattern.contains_scheme = Le motif d'hôte « { $pattern } » ne doit pas inclure de schéma d'URL. +host_pattern.contains_slash = Le motif d'hôte « { $pattern } » ne doit pas contenir « / ». +host_pattern.missing_suffix = Le motif d'hôte « { $pattern } » doit comporter un suffixe après « *. ». +host_pattern.empty_label = Le motif d'hôte « { $pattern } » contient une étiquette vide. +host_pattern.invalid_chars = Le motif d'hôte « { $pattern } » contient des caractères non valides. +host_pattern.invalid_label_edge = Les étiquettes du motif d'hôte « { $pattern } » ne doivent ni commencer ni finir par « - ». +host_pattern.label_too_long = Le motif d'hôte « { $pattern } » contient une étiquette de plus de 63 caractères. +host_pattern.too_long = Le motif d'hôte « { $pattern } » dépasse la limite de 255 caractères. + +# Politique réseau. +network_policy.scheme.empty = Le schéma ne doit pas être vide. +network_policy.scheme.invalid = Le schéma « { $scheme } » contient des caractères non valides. +network_policy.allowlist.empty = La liste d'hôtes autorisés ne doit pas être vide. +network_policy.scheme.not_allowed = Le schéma « { $scheme } » n'est pas autorisé. +network_policy.missing_host = L'URL ne comporte pas d'hôte. +network_policy.host.blocked = L'hôte « { $host } » est bloqué par la politique. +network_policy.host.not_allowlisted = L'hôte « { $host } » ne figure pas dans la liste des hôtes autorisés. + +# Configuration de la bibliothèque standard. +stdlib.config.default_fetch_cache_invalid = Le chemin de cache fetch par défaut doit être relatif. +stdlib.config.default_which_cache_invalid = La capacité de cache which par défaut doit être positive. +stdlib.config.workspace_root_absolute = Le chemin racine de l'espace de travail doit être absolu. +stdlib.config.fetch_response_limit_positive = La limite de réponse de fetch doit être positive. +stdlib.config.command_output_limit_positive = La limite de capture de sortie des commandes doit être positive. +stdlib.config.command_stream_limit_positive = La limite de flux des commandes doit être positive. +stdlib.config.which_cache_capacity_positive = La capacité du cache which doit être positive. +stdlib.config.skip_dir_empty = Les entrées de répertoires à ignorer ne doivent pas être vides. +stdlib.config.skip_dir_navigation = Les entrées de répertoires à ignorer ne doivent pas contenir « .. ». +stdlib.config.skip_dir_separator = Les entrées de répertoires à ignorer ne doivent pas contenir de séparateurs de chemin. +stdlib.config.fetch_cache_empty = Le chemin de cache fetch ne doit pas être vide. +stdlib.config.fetch_cache_not_relative = Le chemin de cache fetch doit être relatif, reçu { $path }. +stdlib.config.fetch_cache_escapes = Le chemin de cache fetch ne doit pas sortir de l'espace de travail : { $path }. +stdlib.config.open_workspace_root = Impossible d'ouvrir le répertoire courant comme racine de l'espace de travail stdlib. +stdlib.config.resolve_cwd = Impossible de résoudre le répertoire courant comme racine de l'espace de travail stdlib. +stdlib.config.cwd_non_utf8 = Le répertoire courant contient des composants non UTF-8 : { $path }. + +# Diagnostics de l'assistant fetch. +stdlib.fetch.url_invalid = URL non valide « { $url } » : { $details }. +stdlib.fetch.disallowed = L'URL « { $url } » n'est pas autorisée : { $details }. +stdlib.fetch.failed = Impossible de récupérer « { $url } » : { $details }. +stdlib.fetch.cache_read_failed = Impossible de lire l'entrée de cache « { $name } » : { $details }. +stdlib.fetch.cache_open_failed = Impossible d'ouvrir l'entrée de cache « { $name } » : { $details }. +stdlib.fetch.response_read_failed = Impossible de lire la réponse de « { $url } » : { $details }. +stdlib.fetch.response_buffer_overflow = Débordement du tampon lors de la lecture de « { $url } ». +stdlib.fetch.cache_write_failed = Impossible d'écrire le cache pour « { $url } » : { $details }. +stdlib.fetch.response_limit_exceeded = La réponse de « { $url } » a dépassé la limite de { $limit } octets. +stdlib.fetch.cache_limit_exceeded = La réponse en cache « { $name } » a dépassé la limite de { $limit } octets. +stdlib.fetch.io_failed = { $action } a échoué pour { $path } : { $details }. +stdlib.fetch.action.sync_cache = synchroniser le cache fetch +stdlib.fetch.action.create_cache_dir = créer le répertoire de cache fetch +stdlib.fetch.action.open_cache_dir = ouvrir le répertoire de cache fetch +stdlib.fetch.action.stat_cache = interroger l'entrée de cache fetch +stdlib.fetch.action.open_cache_entry = ouvrir l'entrée de cache fetch + +# Diagnostics de l'assistant de commandes. +stdlib.command.location = commande « { $command } » dans le gabarit « { $template } » +stdlib.command.spawn_failed = Impossible de lancer { $location } : { $details }. +stdlib.command.io_failed = { $location } a échoué : { $details }. +stdlib.command.closed_input_early = L'entrée s'est fermée avant la fin de l'écriture vers la commande. +stdlib.command.broken_pipe = Tube rompu lors de l'exécution de { $location } : { $details }. +stdlib.command.terminated_by_signal = { $location } a été arrêté par un signal. +stdlib.command.exited_with_status = { $location } s'est terminé avec le statut { $status }. +stdlib.command.output_limit_exceeded = { $location } a dépassé la limite { $mode } de { $limit } octets pour { $stream }. +stdlib.command.timeout = { $location } a dépassé le délai de { $seconds } secondes. +stdlib.command.exit_status_suffix = (statut de sortie { $status }) +stdlib.command.signal_suffix = (arrêté par un signal) +stdlib.command.shell.empty = La commande shell ne doit pas être vide. +stdlib.command.grep.empty_pattern = Le motif grep ne doit pas être vide. +stdlib.command.grep.flags_not_string = Les options de grep doivent être des chaînes. +stdlib.command.quote.invalid = Impossible de protéger { $arg } par des guillemets : { $details }. +stdlib.command.quote.line_break = Les arguments contenant des retours chariot ou des sauts de ligne ne peuvent pas être protégés sans risque. +stdlib.command.input_undefined = La valeur d'entrée est indéfinie. +stdlib.command.tempfile.root_required = La racine de l'espace de travail est requise pour créer des fichiers temporaires de commande. +stdlib.command.tempfile.create_failed = Impossible de créer le fichier temporaire de commande : { $details }. +stdlib.command.options.invalid_utf8 = La clé d'une option de commande doit être de l'UTF-8 valide. +stdlib.command.option.mode_not_string = Le mode de sortie doit être une chaîne. +stdlib.command.options.invalid_type = Les options de commande doivent former un objet. +stdlib.command.output.mode_unsupported = Mode de sortie non pris en charge « { $mode } ». +stdlib.command.output.mode.capture = capture +stdlib.command.output.mode.streaming = flux +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Diagnostics de l'assistant de chemins. +stdlib.path.io.failed = { $action } a échoué pour { $path } ({ $label }). +stdlib.path.io.failed_with_detail = { $action } a échoué pour { $path } : { $detail }. +stdlib.path.io.failed_with_label_and_detail = { $action } a échoué pour { $path } ({ $label }) : { $detail }. +stdlib.path.io.not_found = introuvable +stdlib.path.io.permission_denied = permission refusée +stdlib.path.io.already_exists = existe déjà +stdlib.path.io.invalid_input = entrée non valide +stdlib.path.io.invalid_data = données non valides +stdlib.path.io.timed_out = délai dépassé +stdlib.path.io.interrupted = interrompu +stdlib.path.io.would_block = bloquerait +stdlib.path.io.write_zero = écriture nulle +stdlib.path.io.unexpected_eof = fin de fichier inattendue +stdlib.path.io.broken_pipe = tube rompu +stdlib.path.io.connection_refused = connexion refusée +stdlib.path.io.connection_reset = connexion réinitialisée +stdlib.path.io.connection_aborted = connexion abandonnée +stdlib.path.io.not_connected = non connecté +stdlib.path.io.addr_in_use = adresse déjà utilisée +stdlib.path.io.addr_not_available = adresse non disponible +stdlib.path.io.out_of_memory = mémoire insuffisante +stdlib.path.io.unsupported = non pris en charge +stdlib.path.io.file_too_large = fichier trop volumineux +stdlib.path.io.resource_busy = ressource occupée +stdlib.path.io.executable_busy = exécutable occupé +stdlib.path.io.deadlock = interblocage +stdlib.path.io.crosses_devices = franchit des périphériques +stdlib.path.io.too_many_links = trop de liens +stdlib.path.io.invalid_filename = nom de fichier non valide +stdlib.path.io.arg_list_too_long = liste d'arguments trop longue +stdlib.path.io.stale_handle = descripteur de fichier réseau périmé +stdlib.path.io.storage_full = stockage saturé +stdlib.path.io.not_seekable = positionnement impossible +stdlib.path.io.network_down = réseau hors service +stdlib.path.io.network_unreachable = réseau injoignable +stdlib.path.io.host_unreachable = hôte injoignable +stdlib.path.io.other = erreur d'E/S +stdlib.path.action.canonicalize = canonicaliser +stdlib.path.action.open_directory = ouvrir le répertoire +stdlib.path.action.stat = interroger +stdlib.path.action.read = lire +stdlib.path.action.open_file = ouvrir le fichier +stdlib.path.with_suffix.empty_separator = with_suffix exige un séparateur non vide. +stdlib.path.relative_to.mismatch = { $path } n'est pas relatif à { $root }. +stdlib.path.expanduser.unsupported = L'expansion de ~ propre à un utilisateur n'est pas prise en charge. +stdlib.path.expanduser.no_home = Impossible d'étendre ~ : aucune variable d'environnement de répertoire personnel n'est définie. +stdlib.path.contents.unsupported_encoding = Encodage non pris en charge « { $encoding } ». +stdlib.path.hash.unsupported_algorithm = Algorithme de hachage non pris en charge « { $algorithm } ». +stdlib.path.hash.unsupported_algorithm_legacy = Algorithme de hachage non pris en charge « { $algorithm } » (activez la fonctionnalité « { $feature } »). + +# Diagnostics des assistants de collections. +stdlib.collections.flatten.expected_sequence = flatten attendait des éléments de séquence mais a trouvé { $kind }. +stdlib.collections.group_by.empty_attribute = group_by exige un attribut non vide. +stdlib.collections.group_by.unresolved = group_by n'a pas pu résoudre « { $attr } » sur un élément de type { $kind }. + +# Diagnostics des assistants temporels. +stdlib.time.offset.invalid = Le décalage de now « { $offset } » est non valide : « +HH:MM[:SS] » ou « Z » était attendu. +stdlib.time.timedelta.overflow = Débordement de timedelta lors de l'ajout de { $component }. +stdlib.time.label.weeks = semaines +stdlib.time.label.days = jours +stdlib.time.label.hours = heures +stdlib.time.label.minutes = minutes +stdlib.time.label.seconds = secondes +stdlib.time.label.milliseconds = millisecondes +stdlib.time.label.microseconds = microsecondes +stdlib.time.label.nanoseconds = nanosecondes + +# Diagnostics de l'assistant which. +stdlib.which.not_found = [netsuke::jinja::which::not_found] commande « { $command } » introuvable après examen de { $count } entrées de PATH. Aperçu : { $preview } +stdlib.which.not_found.hint.cwd_auto = Les segments vides de PATH sont ignorés ; utilisez cwd_mode="auto" pour inclure le répertoire de travail. +stdlib.which.not_found.hint.cwd_always = Définissez cwd_mode="always" pour inclure le répertoire courant. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] la commande « { $command } » située dans « { $path } » est absente ou non exécutable. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = L'entrée PATH nº { $index } contient des caractères non UTF-8 ; Netsuke exige des chemins UTF-8. +stdlib.which.command.empty = which exige une chaîne non vide. +stdlib.which.cwd_mode.invalid = cwd_mode doit valoir « auto », « always » ou « never », reçu « { $mode } ». +stdlib.which.cwd.resolve_failed = Impossible de résoudre le répertoire courant : { $details }. +stdlib.which.cwd.non_utf8 = Le répertoire courant contient des composants non UTF-8. +stdlib.which.canonicalize_failed = Impossible de canonicaliser « { $path } » : { $details }. +stdlib.which.is_executable = Impossible de déterminer si « { $path } » est exécutable : { $details }. +stdlib.which.canonicalize_non_utf8 = Le chemin canonique contient des composants non UTF-8. +stdlib.which.workspace_non_utf8 = Le chemin de l'espace de travail contient des composants non UTF-8 lors de la résolution de la commande « { $command } » : { $path }. +stdlib.which.walkdir_error = Erreur de parcours de l'espace de travail pendant la résolution de la commande : { $details }. + +# Enregistrement de la bibliothèque standard. +stdlib.register.open_dir = Impossible d'ouvrir le répertoire courant pour l'enregistrement de la stdlib. +stdlib.register.resolve_dir = Impossible de résoudre le répertoire courant pour l'enregistrement de la stdlib. +stdlib.register.dir_non_utf8 = Le répertoire courant contient des composants non UTF-8 : { $path }. + +# Compte rendu d'état pour le mode de sortie accessible. +status.state.pending = en attente +status.state.running = en cours +status.state.done = terminée +status.state.failed = échouée +status.stage.label = Étape { $current }/{ $total } : { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Tâche { $current }/{ $total } +status.task.progress_update = { $task } : { $description } +status.stage.manifest_ingestion = Lecture du fichier manifeste +status.stage.initial_yaml_parsing = Analyse du document YAML +status.stage.template_expansion = Expansion des directives de gabarit +status.stage.final_rendering = Désérialisation et rendu des valeurs du manifeste +status.stage.ir_generation_validation = Construction et validation du graphe de dépendances +status.stage.ninja_synthesis = Synthèse du plan de compilation Ninja +status.stage.ninja_synthesis_execute = Synthèse du plan Ninja et exécution de { $tool } +status.stage.graph_rendering = Rendu de l'artefact de graphe +status.stage.graph_rendering_with_tool = Rendu de { $tool } +status.complete = { $tool } : opération terminée. +status.timing.summary_header = Résumé des durées par étape : +status.timing.stage_line = - { $label } : { $duration } +status.timing.total_line = Durée totale du pipeline : { $duration } +status.tool.build = Compilation +status.tool.clean = Nettoyage +status.tool.graph = Graphe +status.tool.graph_html = Graphe (HTML) +status.tool.generate = Génération + +# Chaînes du moteur de rendu HTML du graphe. +graph.html.title = Graphe de compilation Netsuke +graph.html.heading = Graphe de compilation Netsuke +graph.html.description = Graphe de compilation restitué par Netsuke +graph.html.outline.summary = Cibles et dépendances (plan textuel) +graph.html.outline.no_inputs = Aucune entrée +graph.html.noscript.notice = JavaScript est désactivé. Le plan textuel ci-dessus contient le graphe complet ; la source DOT suit. + +# Préfixes sémantiques pour la sortie accessible. +semantic.prefix.error = Erreur : +semantic.prefix.warning = Avertissement : +semantic.prefix.success = Succès : +semantic.prefix.info = Info : +semantic.prefix.timing = Durée : +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Exemples de formes plurielles pour les traducteurs. +# Le français utilise les catégories CLDR `one` et `other`, mais `one` couvre +# aussi zéro : « 0 fichier traité » reste au singulier. +example.files_processed = { $count -> + [one] { $count } fichier traité. + *[other] { $count } fichiers traités. +} + +example.errors_found = { $count -> + [0] Aucune erreur trouvée. + [one] { $count } erreur trouvée. + *[other] { $count } erreurs trouvées. +} diff --git a/locales/gd/messages.ftl b/locales/gd/messages.ftl new file mode 100644 index 000000000..84bbdf5f0 --- /dev/null +++ b/locales/gd/messages.ftl @@ -0,0 +1,402 @@ +# Goireasan sgeadachaidh airson loidhne-àithne Netsuke. + +cli.about = Bidh Netsuke a' cur ri chèile foirm-liostaichean YAML + Jinja gu planaichean togail Ninja. +cli.long_about = Bidh Netsuke ag atharrachadh fhoirm-liostaichean YAML + Jinja gu graf Ninja a ghabhas ath-dhèanamh, agus a' ruith Ninja le bun-roghainnean sàbhailte. +cli.usage = { $usage } + +# Teacsa taice nan roghainnean coitcheann. +cli.flag.file.help = An t-slighe gu faidhle foirm-liosta Netsuke ri chleachdadh. +cli.flag.directory.help = Ruith mar gun deach tòiseachadh sa phasgan seo. +cli.flag.config.help = Slighe gu faidhle rèiteachaidh, a' seachnadh an luirg fhèin-obrachail. +cli.flag.jobs.help = Suidhich an àireamh de dh'obraichean togail co-shìnte. +cli.flag.verbose.help = Cuir an comas logadh mionaideach agus geàrr-chunntasan ùine aig deireadh na h-obrach. +cli.flag.locale.help = Taga cànain airson teacsa na loidhne-àithne (mar eisimpleir: en-US, gd). +cli.flag.fetch_allow_scheme.help = Sgeamaichean URL a bharrachd a tha ceadaichte don chuidiche fetch. +cli.flag.fetch_allow_host.help = Ainmean òstairean a tha ceadaichte nuair a tha an diùltadh bunaiteach an gnìomh. +cli.flag.fetch_block_host.help = Ainmean òstairean a thèid a bhacadh an-còmhnaidh, ged a bhiodh iad ceadaichte an àite eile. +cli.flag.fetch_default_deny.help = Diùlt a h-uile òstair mar bhun-roghainn; na ceadaich ach an liosta a chaidh ainmeachadh. +cli.flag.json.help = Cuir a-mach JSON a leughas inneal. +cli.flag.no_input.help = Na leugh cur-a-steach eadar-ghnìomhach idir. +cli.flag.color.help = Poileasaidh an às-chuir dhathte (auto, always, never). +cli.flag.emoji.help = Poileasaidh nan emoji (auto, always, never). +cli.flag.progress.help = Poileasaidh sealltainn an adhartais (auto, always, never). +cli.flag.accessibility.help = Poileasaidh an às-chuir so-ruigsinneach (auto, on, off). +cli.flag.default_targets.help = Targaidean togail bunaiteach nuair nach eil gin air an sònrachadh. + +# Tuairisgeulan nan fo-àitheantan. +cli.subcommand.build.about = Tog na targaidean a tha air am mìneachadh san fhoirm-liosta (bun-roghainn). +cli.subcommand.build.long_about = Tog na targaidean a chaidh iarraidh; mura h-eil gin ann, cleachd targaidean bunaiteach an fhoirm-liosta. +cli.subcommand.clean.about = Thoir air falbh toraidhean an togail tro Ninja. +cli.subcommand.clean.long_about = Dèan faidhle Ninja sealach, agus an uair sin ruith `ninja -t clean`. +cli.subcommand.graph.about = Cuir a-mach graf eisimeileachd an togail. Is e DOT am fòrmat bunaiteach. +cli.subcommand.graph.long_about = Tilg am foirm-liosta Netsuke a chaidh a pharsadh gu graf togail bun-riaghailteach agus sgrìobh e mar Graphviz DOT, no mar dhuilleag HTML fhèin-chuimseach le `--html`. Cleachd `--output ` gus sgrìobhadh gu faidhle; sgrìobhaidh `-` don às-chur àbhaisteach. +cli.subcommand.generate.about = Dèan am foirm-liosta Ninja gun a bhith a' ruith Ninja. +cli.subcommand.generate.long_about = Sgrìobh am foirm-liosta Ninja a chaidh a dhèanamh don às-chur àbhaisteach, no gu faidhle a thaghar le `--output`. + +# Teacsa taice roghainnean an fho-àithne build. +cli.subcommand.build.flag.targets.help = Na targaidean ri thogail (thèid bun-roghainnean an fhoirm-liosta a chleachdadh mura h-eil gin ann). + +# Teacsa taice roghainnean an fho-àithne graph. +cli.subcommand.graph.flag.html.help = Reandaraich an graf mar dhuilleag HTML fhèin-chuimseach seach mar DOT. +cli.subcommand.graph.flag.output.help = Sgrìobh toradh a' ghraf gu FAIDHLE; cleachd `-` airson an às-chuir àbhaistich. + +# Teacsa taice roghainnean an fho-àithne generate. +cli.subcommand.generate.flag.output.help = Sgrìobh am foirm-liosta Ninja a chaidh a dhèanamh gu FAIDHLE seach don às-chur àbhaisteach. + +# Mearachdan dearbhaidh na loidhne-àithne. +cli.validation.jobs.invalid_number = Chan e àireamh dhligheach a th' ann an { $value }. +cli.validation.jobs.out_of_range = Feumaidh àireamh nan obraichean a bhith eadar { $min } agus { $max }. +cli.validation.scheme.empty = Chan fhaod an sgeama a bhith falamh. +cli.validation.scheme.invalid_start = Feumaidh an sgeama “{ $scheme }” tòiseachadh le litir ASCII. +cli.validation.scheme.invalid = Sgeama mì-dhligheach: “{ $scheme }”. +cli.validation.locale.empty = Chan fhaod an taga cànain a bhith falamh. +cli.validation.locale.invalid = Taga cànain mì-dhligheach: “{ $locale }”. +cli.validation.color.invalid = Poileasaidh dhathan mì-dhligheach: “{ $value }”. Roghainnean dligheach: auto, always, never. +cli.validation.emoji.invalid = Poileasaidh emoji mì-dhligheach: “{ $value }”. Roghainnean dligheach: auto, always, never. +cli.validation.progress.invalid = Poileasaidh adhartais mì-dhligheach: “{ $value }”. Roghainnean dligheach: auto, always, never. +cli.validation.accessibility.invalid = Poileasaidh so-ruigsinneachd mì-dhligheach: “{ $value }”. Roghainnean dligheach: auto, on, off. +cli.validation.config.expected_object = Bha dùil gun deigheadh luachan na loidhne-àithne a shreathachadh gu oibseact, ach fhuaireadh { $value }. + +# Teachdaireachdan mearachd Clap. +clap-error-missing-argument = Tha argamaid riatanach a dhìth: { $argument } +clap-error-missing-subcommand = Tha fo-àithne a dhìth. Roghainnean rim faighinn: { $valid_subcommands } +clap-error-unknown-argument = Argamaid neo-aithnichte: { $argument } +clap-error-invalid-value = Luach mì-dhligheach airson { $argument }: { $value } +clap-error-invalid-subcommand = Fo-àithne neo-aithnichte: { $subcommand } +# Nòta: tha faclan value-validation eadar-dhealaichte o invalid-value gus +# fàiligidhean dhearbhairean gnàthaichte (ErrorKind::ValueValidation) a +# sgaradh o mhì-fhreagarrachd sheòrsan (ErrorKind::InvalidValue). +clap-error-value-validation = Dh'fhàillig an dearbhadh airson { $argument }: { $value } + +# Mearachdan agus co-theacsa aig àm ruith. +runner.manifest.not_found = Cha deach am foirm-liosta “{ $manifest_name }” a lorg ann an { $directory }. +runner.manifest.not_found.help = Dèan cinnteach gu bheil am foirm-liosta ann, no thoir seachad `--file` leis an t-slighe cheart. +runner.manifest.path_missing_name = Chan eil ainm faidhle ann an slighe an fhoirm-liosta “{ $path }”. +runner.manifest.path_utf8 = Chan eil slighe an fhoirm-liosta “{ $path }” na UTF-8 dhligheach. +runner.manifest.directory_utf8 = Chan eil slighe pasgan an fhoirm-liosta “{ $path }” na UTF-8 dhligheach. +runner.manifest.directory_label = pasgan `{ $directory }` +runner.manifest.current_directory_label = am pasgan làithreach +runner.context.network_policy = Cha b' urrainnear poileasaidh an lìonraidh a thogail. +runner.context.load_manifest = Cha b' urrainnear am foirm-liosta a luchdachadh o { $path }. +runner.context.serialise_manifest = Cha b' urrainnear am foirm-liosta a shreathachadh. +runner.context.build_graph = Cha b' urrainnear graf a thogail on fhoirm-liosta. +runner.context.generate_ninja = Cha b' urrainnear am foirm-liosta Ninja a dhèanamh. +runner.context.render_graph = Cha b' urrainnear toradh a' ghraf a reandarachadh. + +runner.io.create_temp_file = Cha b' urrainnear am faidhle Ninja sealach a chruthachadh. +runner.io.write_temp_ninja = Cha b' urrainnear sgrìobhadh don fhaidhle Ninja shealach. +runner.io.flush_temp_ninja = Cha b' urrainnear bufair an fhaidhle Ninja shealaich fhalmhachadh. +runner.io.sync_temp_ninja = Cha b' urrainnear am faidhle Ninja sealach a cho-thìmeachadh. +runner.io.create_parent_dir = Cha b' urrainnear am pasgan pàrant { $path } a chruthachadh. +runner.io.create_ninja_file = Cha b' urrainnear faidhle Ninja a chruthachadh aig { $path }. +runner.io.write_ninja_file = Cha b' urrainnear sgrìobhadh don fhaidhle Ninja aig { $path }. +runner.io.flush_ninja_file = Cha b' urrainnear bufair an fhaidhle Ninja aig { $path } fhalmhachadh. +runner.io.sync_ninja_file = Cha b' urrainnear am faidhle Ninja aig { $path } a cho-thìmeachadh. +runner.io.open_ambient_dir = Cha b' urrainnear am pasgan mun cuairt fhosgladh. +runner.io.no_existing_ancestor = Chan eil pasgan sinnsireil ann airson { $path }. +runner.io.derive_relative_path = Cha b' urrainnear slighe Ninja choimeasach a thoirt a-mach. +runner.io.non_utf8_path = Chan eil taic ann do shlighean nach eil nan UTF-8 (slighe: { $path }). +runner.io.write_stdout = Cha b' urrainnear am foirm-liosta Ninja a sgrìobhadh don às-chur àbhaisteach. +runner.io.flush_stdout = Cha b' urrainnear bufair an às-chuir àbhaistich fhalmhachadh. + +# Breithneachadh an fhoirm-liosta. +manifest.parse = Dh'fhàillig parsadh an fhoirm-liosta. +manifest.structure_error = Mearachd structair san fhoirm-liosta aig { $name }: { $details } +manifest.yaml.parse = Mearachd parsaidh YAML air loidhne { $line }, colbh { $column }: { $details } +manifest.yaml.label = YAML mì-dhligheach +manifest.yaml.hint.tabs = Chan eil YAML a' ceadachadh thabaichean; cleachd beàrnan airson eag-thabaidh. +manifest.yaml.hint.list_item = Feumaidh nithean liosta YAML tòiseachadh le “-” agus a bhith air an eagachadh mar bu chòir. +manifest.yaml.hint.expected_colon = Tha coltas mapaidh air seo; tha “:” a dhìth às dèidh na h-iuchrach. +manifest.yaml.hint.mapping_values = Tha mapaidhean YAML ag iarraidh luach às dèidh “:” (no bloca neadaichte). +manifest.yaml.hint.invalid_token = Tha an t-samhla YAML mì-dhligheach no gun dùil ris. +manifest.yaml.hint.escape = Teich na slaisean-cùil no thoir air falbh na sreathan teichidh mì-dhligheach. +manifest.env.missing = Chan eil an caochladair àrainneachd riatanach “{ $name }” air a shuidheachadh. +manifest.env.invalid_utf8 = Tha UTF-8 mì-dhligheach anns a' chaochladair àrainneachd “{ $name }”. +manifest.vars.not_object = Feumaidh `vars` an fhoirm-liosta a bhith na mhapadh no na oibseact. +manifest.read_failed = Cha b' urrainnear am foirm-liosta a leughadh o { $path }. +manifest.resolve_workspace_root = Cha b' urrainnear freumh an raoin-obrach a dhearbhadh. +manifest.workspace_non_utf8 = Chan eil slighe freumh an raoin-obrach “{ $path }” na UTF-8 dhligheach. +manifest.path_non_utf8 = Chan eil slighe an fhoirm-liosta “{ $manifest }” na UTF-8 dhligheach: { $path }. +manifest.path_missing_name = Chan eil ainm faidhle ann an slighe an fhoirm-liosta “{ $path }”. +manifest.open_workspace_failed = Cha b' urrainnear an raon-obrach { $workspace } fhosgladh airson an fhoirm-liosta { $manifest }. +manifest.foreach.not_iterable = Chan urrainnear cuairteachadh thairis air an eas-preisean `foreach`. +manifest.foreach.serialise_item = Cha b' urrainnear nì `foreach` a shreathachadh. +manifest.when.empty = Chan fhaod an eas-preisean `when` a bhith falamh. +manifest.when.eval_error = Cha b' urrainnear an eas-preisean `when` “{ $expr }” a mheasadh. +manifest.when.template_error = Cha b' urrainnear an teamplaid `when` “{ $expr }” a reandarachadh. +manifest.target.vars_not_object = Feumaidh `vars` na targaid a bhith na oibseact, ach fhuaireadh { $value }. +manifest.vars.entry_not_object = Feumaidh innteart `vars` an fhoirm-liosta a bhith na oibseact. +manifest.field_not_string = Feumaidh an raon “{ $field }” a bhith na shreang. +manifest.expression.parse_error = Cha b' urrainnear an eas-preisean { $name } a pharsadh. +manifest.expression.eval_error = Cha b' urrainnear an eas-preisean { $name } a mheasadh. + +# Breithneachadh macros an fhoirm-liosta. +manifest.macro.signature_missing_identifier = Tha aithnichear a dhìth o shoidhneadh a' mhacro. +manifest.macro.signature_missing_params = Tha paramadairean a dhìth o shoidhneadh a' mhacro. +manifest.macro.compile_failed = Cha b' urrainnear am macro { $name } a chur ri chèile. +manifest.macro.sequence_invalid = Feumar macros a mhìneachadh mar mhapadh o ainmean gu teamplaidean. +manifest.macro.register_failed = Cha b' urrainnear macros an fhoirm-liosta a chlàradh. +manifest.macro.not_initialised = Chan eil àrainneachd nam macros air a tòiseachadh. +manifest.macro.caller_invalid = Feumaidh gairmear a' mhacro a bhith na shreang. +manifest.macro.template_load_failed = Cha b' urrainnear teamplaid a' mhacro a luchdachadh. +manifest.macro.init_failed = Cha b' urrainnear àrainneachd nam macros a thòiseachadh. +manifest.macro.missing = Tha am macro { $name } a dhìth. + +# Mearachdan phàtranan glob san fhoirm-liosta. +manifest.glob.unmatched_brace = Pàtran glob mì-dhligheach “{ $pattern }”: chan eil paidhir aig “{ $character }” aig ionad { $position }. +manifest.glob.invalid_pattern = Pàtran glob mì-dhligheach “{ $pattern }”: { $detail }. +manifest.glob.unknown_pattern_error = mearachd phàtrain neo-aithnichte. +manifest.glob.io_failed = Dh'fhàillig glob airson “{ $pattern }”: { $detail }. +manifest.glob.unknown_io_error = mearachd ion-chuir/às-chuir neo-aithnichte. + +# Mearachdan an riochdachaidh mheadhanaich. +ir.rule_not_found = Cha deach an riaghailt “{ $rule }” air a bheil an targaid “{ $target }” a' toirt iomradh a lorg. +ir.multiple_rules = Feumaidh an targaid “{ $target }” iomradh a thoirt air aon riaghailt a-mhàin, ach fhuaireadh { $rules }. +ir.empty_rule = Feumaidh an targaid “{ $target }” iomradh a thoirt air riaghailt. +ir.duplicate_outputs = Chaidh às-chuir dhùblaichte a lorg: { $outputs }. +ir.circular_dependency = Chaidh eisimeileachd chuairteach a lorg: { $cycle }. +ir.action_serialisation = Cha b' urrainnear an gnìomh a shreathachadh: { $details }. +ir.invalid_command = Cur a-steach mì-dhligheach san àithne: { $snippet }. + +# Mearachdan dèanamh Ninja. +ninja_gen.missing_action = Tha an gnìomh “{ $id }” air a bheil oir togail a' toirt iomradh a dhìth. +ninja_gen.format = Cha b' urrainnear às-chur an fhoirm-liosta Ninja fhòrmatadh. + +# Dearbhadh phàtranan òstair. +host_pattern.empty = Chan fhaod pàtran an òstair a bhith falamh. +host_pattern.contains_scheme = Chan fhaod pàtran an òstair “{ $pattern }” sgeama URL a ghabhail a-steach. +host_pattern.contains_slash = Chan fhaod pàtran an òstair “{ $pattern }” “/” a ghabhail a-steach. +host_pattern.missing_suffix = Feumaidh pàtran an òstair “{ $pattern }” iar-leasachan a bhith aige às dèidh “*.”. +host_pattern.empty_label = Tha leubail fhalamh ann am pàtran an òstair “{ $pattern }”. +host_pattern.invalid_chars = Tha caractaran mì-dhligheach ann am pàtran an òstair “{ $pattern }”. +host_pattern.invalid_label_edge = Chan fhaod leubailean pàtran an òstair “{ $pattern }” tòiseachadh no crìochnachadh le “-”. +host_pattern.label_too_long = Tha leubail nas fhaide na 63 caractaran ann am pàtran an òstair “{ $pattern }”. +host_pattern.too_long = Tha pàtran an òstair “{ $pattern }” nas fhaide na crìoch nan 255 caractaran. + +# Poileasaidh an lìonraidh. +network_policy.scheme.empty = Chan fhaod an sgeama a bhith falamh. +network_policy.scheme.invalid = Tha caractaran mì-dhligheach san sgeama “{ $scheme }”. +network_policy.allowlist.empty = Chan fhaod liosta nan òstairean ceadaichte a bhith falamh. +network_policy.scheme.not_allowed = Chan eil an sgeama “{ $scheme }” ceadaichte. +network_policy.missing_host = Tha òstair a dhìth on URL. +network_policy.host.blocked = Tha an t-òstair “{ $host }” air a bhacadh leis a' phoileasaidh. +network_policy.host.not_allowlisted = Chan eil an t-òstair “{ $host }” air liosta nan ceadaichte. + +# Rèiteachadh an leabharlainn àbhaistich. +stdlib.config.default_fetch_cache_invalid = Feumaidh slighe bhunaiteach tasgadan fetch a bhith coimeasach. +stdlib.config.default_which_cache_invalid = Feumaidh tomhas bunaiteach tasgadan which a bhith dearbh. +stdlib.config.workspace_root_absolute = Feumaidh slighe freumh an raoin-obrach a bhith absaloideach. +stdlib.config.fetch_response_limit_positive = Feumaidh crìoch freagairt fetch a bhith dearbh. +stdlib.config.command_output_limit_positive = Feumaidh crìoch glacadh às-chur nan àitheantan a bhith dearbh. +stdlib.config.command_stream_limit_positive = Feumaidh crìoch sruth nan àitheantan a bhith dearbh. +stdlib.config.which_cache_capacity_positive = Feumaidh tomhas tasgadan which a bhith dearbh. +stdlib.config.skip_dir_empty = Chan fhaod innteartan nam pasganan a thèid a leigeil seachad a bhith falamh. +stdlib.config.skip_dir_navigation = Chan fhaod “..” a bhith ann an innteartan nam pasganan a thèid a leigeil seachad. +stdlib.config.skip_dir_separator = Chan fhaod sgaradairean slighe a bhith ann an innteartan nam pasganan a thèid a leigeil seachad. +stdlib.config.fetch_cache_empty = Chan fhaod slighe tasgadan fetch a bhith falamh. +stdlib.config.fetch_cache_not_relative = Feumaidh slighe tasgadan fetch a bhith coimeasach, ach fhuaireadh { $path }. +stdlib.config.fetch_cache_escapes = Chan fhaod slighe tasgadan fetch a dhol a-mach às an raon-obrach: { $path }. +stdlib.config.open_workspace_root = Cha b' urrainnear am pasgan làithreach fhosgladh mar fhreumh raon-obrach stdlib. +stdlib.config.resolve_cwd = Cha b' urrainnear am pasgan làithreach a dhearbhadh mar fhreumh raon-obrach stdlib. +stdlib.config.cwd_non_utf8 = Tha pàirtean anns a' phasgan làithreach nach eil nan UTF-8: { $path }. + +# Breithneachadh a' chuidiche fetch. +stdlib.fetch.url_invalid = URL mì-dhligheach “{ $url }”: { $details }. +stdlib.fetch.disallowed = Chan eil an URL “{ $url }” ceadaichte: { $details }. +stdlib.fetch.failed = Cha b' urrainnear “{ $url }” fhaighinn: { $details }. +stdlib.fetch.cache_read_failed = Cha b' urrainnear innteart an tasgadain “{ $name }” a leughadh: { $details }. +stdlib.fetch.cache_open_failed = Cha b' urrainnear innteart an tasgadain “{ $name }” fhosgladh: { $details }. +stdlib.fetch.response_read_failed = Cha b' urrainnear an fhreagairt o “{ $url }” a leughadh: { $details }. +stdlib.fetch.response_buffer_overflow = Chuir am bufair thairis fhad 's a bhathar a' leughadh “{ $url }”. +stdlib.fetch.cache_write_failed = Cha b' urrainnear an tasgadan airson “{ $url }” a sgrìobhadh: { $details }. +stdlib.fetch.response_limit_exceeded = Chaidh an fhreagairt o “{ $url }” thairis air crìoch { $limit } baidht. +stdlib.fetch.cache_limit_exceeded = Chaidh an fhreagairt thasgte “{ $name }” thairis air crìoch { $limit } baidht. +stdlib.fetch.io_failed = Dh'fhàillig an gnìomh “{ $action }” airson { $path }: { $details }. +stdlib.fetch.action.sync_cache = co-thìmeachadh tasgadan fetch +stdlib.fetch.action.create_cache_dir = cruthachadh pasgan tasgadan fetch +stdlib.fetch.action.open_cache_dir = fosgladh pasgan tasgadan fetch +stdlib.fetch.action.stat_cache = leughadh fiosrachadh innteart tasgadan fetch +stdlib.fetch.action.open_cache_entry = fosgladh innteart tasgadan fetch + +# Breithneachadh cuidiche nan àitheantan. +stdlib.command.location = an àithne “{ $command }” san teamplaid “{ $template }” +stdlib.command.spawn_failed = Cha b' urrainnear { $location } a thòiseachadh: { $details }. +stdlib.command.io_failed = Dh'fhàillig { $location }: { $details }. +stdlib.command.closed_input_early = Dhùin an cur-a-steach mus deach an sgrìobhadh don àithne a chrìochnachadh. +stdlib.command.broken_pipe = Bhris a' phìob fhad 's a bhathar a' ruith { $location }: { $details }. +stdlib.command.terminated_by_signal = Chaidh { $location } a chrìochnachadh le comharra. +stdlib.command.exited_with_status = Thàinig { $location } gu crìch le staid { $status }. +stdlib.command.output_limit_exceeded = Chaidh { $location } thairis air crìoch { $mode } de { $limit } baidht airson { $stream }. +stdlib.command.timeout = Chaidh { $location } thairis air crìoch-ùine de { $seconds } diog. +stdlib.command.exit_status_suffix = (staid fàgail { $status }) +stdlib.command.signal_suffix = (air a chrìochnachadh le comharra) +stdlib.command.shell.empty = Chan fhaod àithne na slige a bhith falamh. +stdlib.command.grep.empty_pattern = Chan fhaod pàtran grep a bhith falamh. +stdlib.command.grep.flags_not_string = Feumaidh brataichean grep a bhith nan sreangan. +stdlib.command.quote.invalid = Cha b' urrainnear { $arg } a chur ann an comharran-labhairt: { $details }. +stdlib.command.quote.line_break = Chan urrainnear argamaidean le tilleadh-carbaid no briseadh-loidhne a chur ann an comharran-labhairt gu sàbhailte. +stdlib.command.input_undefined = Chan eil luach a' chuir-a-steach air a mhìneachadh. +stdlib.command.tempfile.root_required = Tha feum air freumh an raoin-obrach gus faidhlichean àithne sealach a chruthachadh. +stdlib.command.tempfile.create_failed = Cha b' urrainnear faidhle sealach na h-àithne a chruthachadh: { $details }. +stdlib.command.options.invalid_utf8 = Feumaidh iuchair roghainn na h-àithne a bhith na UTF-8 dhligheach. +stdlib.command.option.mode_not_string = Feumaidh am modh às-chuir a bhith na shreang. +stdlib.command.options.invalid_type = Feumaidh roghainnean na h-àithne a bhith nan oibseact. +stdlib.command.output.mode_unsupported = Modh às-chuir gun taic: “{ $mode }”. +stdlib.command.output.mode.capture = glacadh +stdlib.command.output.mode.streaming = sruthadh +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Breithneachadh cuidiche nan slighean. +stdlib.path.io.failed = Dh'fhàillig an gnìomh “{ $action }” airson { $path } ({ $label }). +stdlib.path.io.failed_with_detail = Dh'fhàillig an gnìomh “{ $action }” airson { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = Dh'fhàillig an gnìomh “{ $action }” airson { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = cha deach a lorg +stdlib.path.io.permission_denied = chaidh cead a dhiùltadh +stdlib.path.io.already_exists = ann mu thràth +stdlib.path.io.invalid_input = cur-a-steach mì-dhligheach +stdlib.path.io.invalid_data = dàta mì-dhligheach +stdlib.path.io.timed_out = dh'fhalbh an ùine +stdlib.path.io.interrupted = air a bhriseadh a-steach +stdlib.path.io.would_block = bhacadh e an obair +stdlib.path.io.write_zero = chaidh neoni baidht a sgrìobhadh +stdlib.path.io.unexpected_eof = deireadh faidhle gun dùil ris +stdlib.path.io.broken_pipe = pìob bhriste +stdlib.path.io.connection_refused = chaidh an ceangal a dhiùltadh +stdlib.path.io.connection_reset = chaidh an ceangal ath-shuidheachadh +stdlib.path.io.connection_aborted = chaidh an ceangal a sgur +stdlib.path.io.not_connected = gun cheangal +stdlib.path.io.addr_in_use = tha an seòladh ga chleachdadh +stdlib.path.io.addr_not_available = chan eil an seòladh ri fhaighinn +stdlib.path.io.out_of_memory = dh'fhalbh an cuimhne +stdlib.path.io.unsupported = gun taic +stdlib.path.io.file_too_large = tha am faidhle ro mhòr +stdlib.path.io.resource_busy = tha an goireas trang +stdlib.path.io.executable_busy = tha am faidhle so-ruithe trang +stdlib.path.io.deadlock = glasadh marbh +stdlib.path.io.crosses_devices = a' dol tarsainn air innealan +stdlib.path.io.too_many_links = cus cheanglaichean +stdlib.path.io.invalid_filename = ainm faidhle mì-dhligheach +stdlib.path.io.arg_list_too_long = tha liosta nan argamaidean ro fhada +stdlib.path.io.stale_handle = làmhrachan faidhle lìonraidh sean +stdlib.path.io.storage_full = tha an stòras làn +stdlib.path.io.not_seekable = cha ghabh ionad a shuidheachadh +stdlib.path.io.network_down = tha an lìonra sìos +stdlib.path.io.network_unreachable = cha ruigear an lìonra +stdlib.path.io.host_unreachable = cha ruigear an t-òstair +stdlib.path.io.other = mearachd ion-chuir/às-chuir +stdlib.path.action.canonicalize = bun-riaghailteachadh +stdlib.path.action.open_directory = fosgladh pasgain +stdlib.path.action.stat = leughadh fiosrachaidh +stdlib.path.action.read = leughadh +stdlib.path.action.open_file = fosgladh faidhle +stdlib.path.with_suffix.empty_separator = Tha with_suffix ag iarraidh sgaradair nach eil falamh. +stdlib.path.relative_to.mismatch = Chan eil { $path } coimeasach ri { $root }. +stdlib.path.expanduser.unsupported = Chan eil taic ann do leudachadh ~ airson cleachdaiche sònraichte. +stdlib.path.expanduser.no_home = Chan urrainnear ~ a leudachadh: chan eil caochladair àrainneachd sam bith ann airson a' phasgain dhachaigh. +stdlib.path.contents.unsupported_encoding = Còdachadh gun taic: “{ $encoding }”. +stdlib.path.hash.unsupported_algorithm = Algairim hais gun taic: “{ $algorithm }”. +stdlib.path.hash.unsupported_algorithm_legacy = Algairim hais gun taic: “{ $algorithm }” (cuir an comas am feart “{ $feature }”). + +# Breithneachadh chuidichean nan cruinneachaidhean. +stdlib.collections.flatten.expected_sequence = Bha dùil aig flatten ri nithean sreath ach fhuair e { $kind }. +stdlib.collections.group_by.empty_attribute = Tha group_by ag iarraidh buadh nach eil falamh. +stdlib.collections.group_by.unresolved = Cha b' urrainn do group_by “{ $attr }” a lorg air nì den t-seòrsa { $kind }. + +# Breithneachadh chuidichean na h-ùine. +stdlib.time.offset.invalid = Tha frith-ùine now “{ $offset }” mì-dhligheach: bha dùil ri “+HH:MM[:SS]” no “Z”. +stdlib.time.timedelta.overflow = Chuir timedelta thairis nuair a chaidh { $component } a chur ris. +stdlib.time.label.weeks = seachdainean +stdlib.time.label.days = làithean +stdlib.time.label.hours = uairean +stdlib.time.label.minutes = mionaidean +stdlib.time.label.seconds = diogan +stdlib.time.label.milliseconds = mille-dhiogan +stdlib.time.label.microseconds = meanbh-dhiogan +stdlib.time.label.nanoseconds = nano-dhiogan + +# Breithneachadh a' chuidiche which. +stdlib.which.not_found = [netsuke::jinja::which::not_found] cha deach an àithne “{ $command }” a lorg às dèidh { $count } innteart PATH a sgrùdadh. Ro-shealladh: { $preview } +stdlib.which.not_found.hint.cwd_auto = Thèid earrannan falamh de PATH a leigeil seachad; cleachd cwd_mode="auto" gus am pasgan obrach a ghabhail a-steach. +stdlib.which.not_found.hint.cwd_always = Suidhich cwd_mode="always" gus am pasgan làithreach a ghabhail a-steach. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] tha an àithne “{ $command }” aig “{ $path }” a dhìth no chan eil i so-ruithe. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = Tha caractaran nach eil nan UTF-8 ann an innteart àireamh { $index } de PATH; tha Netsuke ag iarraidh slighean UTF-8. +stdlib.which.command.empty = Tha which ag iarraidh sreang nach eil falamh. +stdlib.which.cwd_mode.invalid = Feumaidh cwd_mode a bhith na “auto”, “always” no “never”, ach fhuaireadh “{ $mode }”. +stdlib.which.cwd.resolve_failed = Cha b' urrainnear am pasgan làithreach a dhearbhadh: { $details }. +stdlib.which.cwd.non_utf8 = Tha pàirtean anns a' phasgan làithreach nach eil nan UTF-8. +stdlib.which.canonicalize_failed = Cha b' urrainnear “{ $path }” a bhun-riaghailteachadh: { $details }. +stdlib.which.is_executable = Cha b' urrainnear dearbhadh a bheil “{ $path }” so-ruithe: { $details }. +stdlib.which.canonicalize_non_utf8 = Tha pàirtean san t-slighe bhun-riaghailtich nach eil nan UTF-8. +stdlib.which.workspace_non_utf8 = Tha pàirtean ann an slighe an raoin-obrach nach eil nan UTF-8 nuair a bhathar a' fuasgladh na h-àithne “{ $command }”: { $path }. +stdlib.which.walkdir_error = Mearachd a' siubhal an raoin-obrach nuair a bhathar a' fuasgladh na h-àithne: { $details }. + +# Clàradh an leabharlainn àbhaistich. +stdlib.register.open_dir = Cha b' urrainnear am pasgan làithreach fhosgladh airson clàradh stdlib. +stdlib.register.resolve_dir = Cha b' urrainnear am pasgan làithreach a dhearbhadh airson clàradh stdlib. +stdlib.register.dir_non_utf8 = Tha pàirtean anns a' phasgan làithreach nach eil nan UTF-8: { $path }. + +# Aithris staide airson a' mhodh às-chuir so-ruigsinnich. +status.state.pending = a' feitheamh +status.state.running = a' dol air adhart +status.state.done = deiseil +status.state.failed = dh'fhàillig +status.stage.label = Ceum { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Obair { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = A' leughadh faidhle an fhoirm-liosta +status.stage.initial_yaml_parsing = A' parsadh na sgrìobhainn YAML +status.stage.template_expansion = A' leudachadh stiùiridhean nan teamplaidean +status.stage.final_rendering = A' dì-shreathachadh 's a' reandarachadh luachan an fhoirm-liosta +status.stage.ir_generation_validation = A' togail 's a' dearbhadh graf nan eisimeileachdan +status.stage.ninja_synthesis = A' cur ri chèile plana togail Ninja +status.stage.ninja_synthesis_execute = A' cur ri chèile plana Ninja 's a' ruith { $tool } +status.stage.graph_rendering = A' reandarachadh toradh a' ghraf +status.stage.graph_rendering_with_tool = A' reandarachadh { $tool } +status.complete = Chaidh { $tool } a chrìochnachadh. +status.timing.summary_header = Geàrr-chunntas ùine a rèir ceum: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Ùine iomlan na loidhne-obrach: { $duration } +status.tool.build = Togail +status.tool.clean = Glanadh +status.tool.graph = Graf +status.tool.graph_html = Graf (HTML) +status.tool.generate = Dèanamh + +# Sreangan reandaraiche HTML a' ghraf. +graph.html.title = Graf togail Netsuke +graph.html.heading = Graf togail Netsuke +graph.html.description = Graf togail a chaidh a reandarachadh le Netsuke +graph.html.outline.summary = Targaidean agus eisimeileachdan (dealbh teacsa) +graph.html.outline.no_inputs = Gun chur-a-steach +graph.html.noscript.notice = Tha JavaScript à comas. Is e an dealbh teacsa gu h-àrd an graf gu lèir; leanaidh tùs DOT air a shàilean. + +# Ro-leasachain bhrìgheil airson an às-chuir so-ruigsinnich. +semantic.prefix.error = Mearachd: +semantic.prefix.warning = Rabhadh: +semantic.prefix.success = Soirbheas: +semantic.prefix.info = Fiosrachadh: +semantic.prefix.timing = Ùine: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Eisimpleirean de na foirmean iolra do dh'eadar-theangairean. +# Tha ceithir roinnean CLDR aig a' Ghàidhlig: `one` (1, 11), `two` (2, 12), +# `few` (3–10, 13–19) agus `other`, agus tha an t-ainmear ag atharrachadh. +example.files_processed = { $count -> + [one] Chaidh { $count } fhaidhle a phròiseasadh. + [two] Chaidh { $count } fhaidhle a phròiseasadh. + [few] Chaidh { $count } faidhlichean a phròiseasadh. + *[other] Chaidh { $count } faidhle a phròiseasadh. +} + +example.errors_found = { $count -> + [0] Cha deach mearachd sam bith a lorg. + [one] Chaidh { $count } mhearachd a lorg. + [two] Chaidh { $count } mhearachd a lorg. + [few] Chaidh { $count } mearachdan a lorg. + *[other] Chaidh { $count } mearachd a lorg. +} diff --git a/locales/he/messages.ftl b/locales/he/messages.ftl new file mode 100644 index 000000000..123f47406 --- /dev/null +++ b/locales/he/messages.ftl @@ -0,0 +1,402 @@ +# משאבי לוקליזציה לשורת הפקודה של Netsuke. + +cli.about = ‏Netsuke מהדר מניפסטים של YAML + Jinja לתוכניות בנייה של Ninja. +cli.long_about = ‏Netsuke ממיר מניפסטים של YAML + Jinja לגרפים ברי‑שחזור של Ninja ומריץ את Ninja עם ברירות מחדל בטוחות. +cli.usage = { $usage } + +# טקסט העזרה של האפשרויות הכלליות. +cli.flag.file.help = הנתיב לקובץ המניפסט של Netsuke שיש להשתמש בו. +cli.flag.directory.help = הרצה כאילו ההפעלה התרחשה בספרייה זו. +cli.flag.config.help = הנתיב לקובץ תצורה, תוך עקיפת החיפוש האוטומטי. +cli.flag.jobs.help = קביעת מספר משימות הבנייה המקבילות. +cli.flag.verbose.help = הפעלת רישום אבחון מפורט וסיכומי זמן בסיום. +cli.flag.locale.help = תג השפה של טקסטי שורת הפקודה (למשל: en-US, he). +cli.flag.fetch_allow_scheme.help = סכימות URL נוספות המותרות לעוזר fetch. +cli.flag.fetch_allow_host.help = שמות מארחים המותרים כאשר הדחייה כברירת מחדל פעילה. +cli.flag.fetch_block_host.help = שמות מארחים החסומים תמיד, גם אם הותרו במקום אחר. +cli.flag.fetch_default_deny.help = דחיית כל המארחים כברירת מחדל; התרת הרשימה המוצהרת בלבד. +cli.flag.json.help = פלט JSON הניתן לקריאה במכונה. +cli.flag.no_input.help = לעולם לא לקרוא קלט אינטראקטיבי. +cli.flag.color.help = מדיניות הפלט הצבעוני (auto, always, never). +cli.flag.emoji.help = מדיניות האמוג׳י (auto, always, never). +cli.flag.progress.help = מדיניות הצגת ההתקדמות (auto, always, never). +cli.flag.accessibility.help = מדיניות הפלט הנגיש (auto, on, off). +cli.flag.default_targets.help = יעדי הבנייה המשמשים כברירת מחדל כאשר לא צוין יעד. + +# תיאורי פקודות המשנה. +cli.subcommand.build.about = בניית היעדים המוגדרים במניפסט (ברירת מחדל). +cli.subcommand.build.long_about = בניית היעדים המבוקשים; אם לא צוין יעד, נעשה שימוש ביעדי ברירת המחדל של המניפסט. +cli.subcommand.clean.about = הסרת תוצרי הבנייה באמצעות Ninja. +cli.subcommand.clean.long_about = יצירת קובץ Ninja זמני ולאחר מכן הרצת `ninja -t clean`. +cli.subcommand.graph.about = פלט גרף התלויות של הבנייה. תבנית ברירת המחדל היא DOT. +cli.subcommand.graph.long_about = הטלת המניפסט המנותח של Netsuke לגרף בנייה קנוני וכתיבתו כ‑Graphviz DOT, או כדף HTML עצמאי עם `--html`. השתמשו ב‑`--output <קובץ>` לכתיבה לקובץ; `-` כותב לפלט התקני. +cli.subcommand.generate.about = יצירת מניפסט Ninja בלי להריץ את Ninja. +cli.subcommand.generate.long_about = כתיבת מניפסט Ninja שנוצר לפלט התקני או לקובץ שנבחר באמצעות `--output`. + +# טקסט העזרה של אפשרויות פקודת המשנה build. +cli.subcommand.build.flag.targets.help = היעדים שיש לבנות (בהשמטה נעשה שימוש בברירות המחדל של המניפסט). + +# טקסט העזרה של אפשרויות פקודת המשנה graph. +cli.subcommand.graph.flag.html.help = עיבוד הגרף כדף HTML עצמאי במקום כ‑DOT. +cli.subcommand.graph.flag.output.help = כתיבת תוצר הגרף לקובץ; לפלט התקני השתמשו ב‑`-`. + +# טקסט העזרה של אפשרויות פקודת המשנה generate. +cli.subcommand.generate.flag.output.help = כתיבת מניפסט Ninja שנוצר לקובץ במקום לפלט התקני. + +# שגיאות אימות בשורת הפקודה. +cli.validation.jobs.invalid_number = ‏{ $value } אינו מספר תקין. +cli.validation.jobs.out_of_range = מספר המשימות חייב להיות בין { $min } ל‑{ $max }. +cli.validation.scheme.empty = הסכימה אינה יכולה להיות ריקה. +cli.validation.scheme.invalid_start = הסכימה „{ $scheme }” חייבת להתחיל באות ASCII. +cli.validation.scheme.invalid = סכימה לא תקינה: „{ $scheme }”. +cli.validation.locale.empty = תג השפה אינו יכול להיות ריק. +cli.validation.locale.invalid = תג שפה לא תקין: „{ $locale }”. +cli.validation.color.invalid = מדיניות צבע לא תקינה: „{ $value }”. ערכים תקפים: auto, always, never. +cli.validation.emoji.invalid = מדיניות אמוג׳י לא תקינה: „{ $value }”. ערכים תקפים: auto, always, never. +cli.validation.progress.invalid = מדיניות התקדמות לא תקינה: „{ $value }”. ערכים תקפים: auto, always, never. +cli.validation.accessibility.invalid = מדיניות נגישות לא תקינה: „{ $value }”. ערכים תקפים: auto, on, off. +cli.validation.config.expected_object = ערכי שורת הפקודה היו אמורים לעבור סריאליזציה לאובייקט, אך התקבל { $value }. + +# הודעות השגיאה של Clap. +clap-error-missing-argument = חסר ארגומנט נדרש: { $argument } +clap-error-missing-subcommand = חסרה פקודת משנה. האפשרויות הזמינות: { $valid_subcommands } +clap-error-unknown-argument = ארגומנט לא מוכר: { $argument } +clap-error-invalid-value = ערך לא תקין עבור { $argument }: { $value } +clap-error-invalid-subcommand = פקודת משנה לא מוכרת: { $subcommand } +# הערה: הניסוח של value-validation שונה מזה של invalid-value כדי להבחין בין +# כשלים של מאמתים מותאמים (ErrorKind::ValueValidation) לבין אי‑התאמת טיפוסים +# (ErrorKind::InvalidValue). +clap-error-value-validation = האימות של { $argument } נכשל: { $value } + +# שגיאות והקשר בזמן ריצה. +runner.manifest.not_found = המניפסט „{ $manifest_name }” לא נמצא ב‑{ $directory }. +runner.manifest.not_found.help = ודאו שהמניפסט קיים או ציינו `--file` עם הנתיב הנכון. +runner.manifest.path_missing_name = לנתיב המניפסט „{ $path }” אין שם קובץ. +runner.manifest.path_utf8 = נתיב המניפסט „{ $path }” אינו UTF-8 תקין. +runner.manifest.directory_utf8 = נתיב ספריית המניפסט „{ $path }” אינו UTF-8 תקין. +runner.manifest.directory_label = הספרייה `{ $directory }` +runner.manifest.current_directory_label = הספרייה הנוכחית +runner.context.network_policy = לא ניתן היה לבנות את מדיניות הרשת. +runner.context.load_manifest = לא ניתן היה לטעון את המניפסט מ‑{ $path }. +runner.context.serialise_manifest = לא ניתן היה לבצע סריאליזציה למניפסט. +runner.context.build_graph = לא ניתן היה לבנות גרף מהמניפסט. +runner.context.generate_ninja = לא ניתן היה ליצור את מניפסט Ninja. +runner.context.render_graph = לא ניתן היה לעבד את תוצר הגרף. + +runner.io.create_temp_file = לא ניתן היה ליצור את קובץ Ninja הזמני. +runner.io.write_temp_ninja = לא ניתן היה לכתוב לקובץ Ninja הזמני. +runner.io.flush_temp_ninja = לא ניתן היה לרוקן את החוצץ של קובץ Ninja הזמני. +runner.io.sync_temp_ninja = לא ניתן היה לסנכרן את קובץ Ninja הזמני. +runner.io.create_parent_dir = לא ניתן היה ליצור את ספריית האב { $path }. +runner.io.create_ninja_file = לא ניתן היה ליצור את קובץ Ninja ב‑{ $path }. +runner.io.write_ninja_file = לא ניתן היה לכתוב לקובץ Ninja ב‑{ $path }. +runner.io.flush_ninja_file = לא ניתן היה לרוקן את החוצץ של קובץ Ninja ב‑{ $path }. +runner.io.sync_ninja_file = לא ניתן היה לסנכרן את קובץ Ninja ב‑{ $path }. +runner.io.open_ambient_dir = לא ניתן היה לפתוח את הספרייה הסובבת. +runner.io.no_existing_ancestor = אין ספריית אב קיימת עבור { $path }. +runner.io.derive_relative_path = לא ניתן היה לגזור את נתיב Ninja היחסי. +runner.io.non_utf8_path = נתיבים שאינם UTF-8 אינם נתמכים (נתיב: { $path }). +runner.io.write_stdout = לא ניתן היה לכתוב את מניפסט Ninja לפלט התקני. +runner.io.flush_stdout = לא ניתן היה לרוקן את החוצץ של הפלט התקני. + +# אבחון המניפסט. +manifest.parse = ניתוח המניפסט נכשל. +manifest.structure_error = שגיאת מבנה במניפסט ב‑{ $name }: { $details } +manifest.yaml.parse = שגיאת ניתוח YAML בשורה { $line }, בעמודה { $column }: { $details } +manifest.yaml.label = ‏YAML לא תקין +manifest.yaml.hint.tabs = ‏YAML אינו מתיר תווי טאב; השתמשו ברווחים להזחה. +manifest.yaml.hint.list_item = פריטי רשימה ב‑YAML חייבים להתחיל ב‑„-” ולהיות מוזחים כראוי. +manifest.yaml.hint.expected_colon = זה נראה כמו רשומת מיפוי; חסר „:” אחרי המפתח. +manifest.yaml.hint.mapping_values = מיפויים ב‑YAML דורשים ערך אחרי „:” (או בלוק מקונן). +manifest.yaml.hint.invalid_token = אסימון ה‑YAML אינו תקין או אינו צפוי. +manifest.yaml.hint.escape = בצעו מילוט ללוכסנים אחוריים או הסירו רצפי מילוט לא תקינים. +manifest.env.missing = משתנה הסביבה הנדרש „{ $name }” אינו מוגדר. +manifest.env.invalid_utf8 = משתנה הסביבה „{ $name }” מכיל UTF-8 לא תקין. +manifest.vars.not_object = השדה `vars` של המניפסט חייב להיות מיפוי או אובייקט. +manifest.read_failed = לא ניתן היה לקרוא את המניפסט מ‑{ $path }. +manifest.resolve_workspace_root = לא ניתן היה לקבוע את שורש סביבת העבודה. +manifest.workspace_non_utf8 = נתיב השורש של סביבת העבודה „{ $path }” אינו UTF-8 תקין. +manifest.path_non_utf8 = הנתיב של המניפסט „{ $manifest }” אינו UTF-8 תקין: { $path }. +manifest.path_missing_name = לנתיב המניפסט „{ $path }” אין שם קובץ. +manifest.open_workspace_failed = לא ניתן היה לפתוח את סביבת העבודה { $workspace } עבור המניפסט { $manifest }. +manifest.foreach.not_iterable = הביטוי `foreach` אינו ניתן למעבר. +manifest.foreach.serialise_item = לא ניתן היה לבצע סריאליזציה לפריט של `foreach`. +manifest.when.empty = הביטוי `when` אינו יכול להיות ריק. +manifest.when.eval_error = לא ניתן היה להעריך את הביטוי `when` „{ $expr }”. +manifest.when.template_error = לא ניתן היה לעבד את התבנית `when` „{ $expr }”. +manifest.target.vars_not_object = השדה `vars` של היעד חייב להיות אובייקט, אך התקבל { $value }. +manifest.vars.entry_not_object = רשומת `vars` של המניפסט חייבת להיות אובייקט. +manifest.field_not_string = השדה „{ $field }” חייב להיות מחרוזת. +manifest.expression.parse_error = לא ניתן היה לנתח את הביטוי { $name }. +manifest.expression.eval_error = לא ניתן היה להעריך את הביטוי { $name }. + +# אבחון המאקרו של המניפסט. +manifest.macro.signature_missing_identifier = בחתימת המאקרו חסר מזהה. +manifest.macro.signature_missing_params = בחתימת המאקרו חסרים פרמטרים. +manifest.macro.compile_failed = לא ניתן היה להדר את המאקרו { $name }. +manifest.macro.sequence_invalid = יש להגדיר מאקרו כמיפוי משמות לתבניות. +manifest.macro.register_failed = לא ניתן היה לרשום את המאקרו של המניפסט. +manifest.macro.not_initialised = סביבת המאקרו אינה מאותחלת. +manifest.macro.caller_invalid = הקורא למאקרו חייב להיות מחרוזת. +manifest.macro.template_load_failed = לא ניתן היה לטעון את תבנית המאקרו. +manifest.macro.init_failed = לא ניתן היה לאתחל את סביבת המאקרו. +manifest.macro.missing = המאקרו { $name } חסר. + +# שגיאות תבניות glob במניפסט. +manifest.glob.unmatched_brace = תבנית glob לא תקינה „{ $pattern }”: התו „{ $character }” בלא זוג במיקום { $position }. +manifest.glob.invalid_pattern = תבנית glob לא תקינה „{ $pattern }”: { $detail }. +manifest.glob.unknown_pattern_error = שגיאת תבנית לא ידועה. +manifest.glob.io_failed = ‏glob נכשל עבור „{ $pattern }”: { $detail }. +manifest.glob.unknown_io_error = שגיאת קלט/פלט לא ידועה. + +# שגיאות הייצוג הביניימי. +ir.rule_not_found = הכלל „{ $rule }” שאליו מפנה היעד „{ $target }” לא נמצא. +ir.multiple_rules = היעד „{ $target }” חייב להפנות לכלל אחד בלבד, אך התקבל { $rules }. +ir.empty_rule = היעד „{ $target }” חייב להפנות לכלל. +ir.duplicate_outputs = זוהו פלטים כפולים: { $outputs }. +ir.circular_dependency = זוהתה תלות מעגלית: { $cycle }. +ir.action_serialisation = לא ניתן היה לבצע סריאליזציה לפעולה: { $details }. +ir.invalid_command = שיבוץ לא תקין בפקודה: { $snippet }. + +# שגיאות ביצירת קובצי Ninja. +ninja_gen.missing_action = הפעולה „{ $id }” שאליה מפנה קשת בנייה חסרה. +ninja_gen.format = לא ניתן היה לעצב את פלט מניפסט Ninja. + +# אימות תבניות מארח. +host_pattern.empty = תבנית המארח אינה יכולה להיות ריקה. +host_pattern.contains_scheme = תבנית המארח „{ $pattern }” אינה יכולה לכלול סכימת URL. +host_pattern.contains_slash = תבנית המארח „{ $pattern }” אינה יכולה לכלול „/”. +host_pattern.missing_suffix = תבנית המארח „{ $pattern }” חייבת לכלול סיומת אחרי „*.”. +host_pattern.empty_label = תבנית המארח „{ $pattern }” מכילה תווית ריקה. +host_pattern.invalid_chars = תבנית המארח „{ $pattern }” מכילה תווים לא תקינים. +host_pattern.invalid_label_edge = תוויות של תבנית המארח „{ $pattern }” אינן יכולות להתחיל או להסתיים ב‑„-”. +host_pattern.label_too_long = תבנית המארח „{ $pattern }” מכילה תווית ארוכה מ‑63 תווים. +host_pattern.too_long = תבנית המארח „{ $pattern }” חורגת ממגבלת 255 התווים. + +# מדיניות הרשת. +network_policy.scheme.empty = הסכימה אינה יכולה להיות ריקה. +network_policy.scheme.invalid = הסכימה „{ $scheme }” מכילה תווים לא תקינים. +network_policy.allowlist.empty = רשימת המארחים המותרים אינה יכולה להיות ריקה. +network_policy.scheme.not_allowed = הסכימה „{ $scheme }” אינה מותרת. +network_policy.missing_host = בכתובת ה‑URL חסר מארח. +network_policy.host.blocked = המארח „{ $host }” חסום על ידי המדיניות. +network_policy.host.not_allowlisted = המארח „{ $host }” אינו ברשימת המותרים. + +# תצורת הספרייה התקנית. +stdlib.config.default_fetch_cache_invalid = נתיב ברירת המחדל של מטמון fetch חייב להיות יחסי. +stdlib.config.default_which_cache_invalid = קיבולת ברירת המחדל של מטמון which חייבת להיות חיובית. +stdlib.config.workspace_root_absolute = נתיב השורש של סביבת העבודה חייב להיות מוחלט. +stdlib.config.fetch_response_limit_positive = מגבלת התגובה של fetch חייבת להיות חיובית. +stdlib.config.command_output_limit_positive = מגבלת לכידת פלט הפקודות חייבת להיות חיובית. +stdlib.config.command_stream_limit_positive = מגבלת הזרימה של הפקודות חייבת להיות חיובית. +stdlib.config.which_cache_capacity_positive = קיבולת מטמון which חייבת להיות חיובית. +stdlib.config.skip_dir_empty = רשומות הספריות המדולגות אינן יכולות להיות ריקות. +stdlib.config.skip_dir_navigation = רשומות הספריות המדולגות אינן יכולות להכיל „..”. +stdlib.config.skip_dir_separator = רשומות הספריות המדולגות אינן יכולות להכיל מפרידי נתיב. +stdlib.config.fetch_cache_empty = נתיב מטמון fetch אינו יכול להיות ריק. +stdlib.config.fetch_cache_not_relative = נתיב מטמון fetch חייב להיות יחסי, אך התקבל { $path }. +stdlib.config.fetch_cache_escapes = נתיב מטמון fetch אינו יכול לצאת מסביבת העבודה: { $path }. +stdlib.config.open_workspace_root = לא ניתן היה לפתוח את הספרייה הנוכחית כשורש סביבת העבודה של stdlib. +stdlib.config.resolve_cwd = לא ניתן היה לקבוע את הספרייה הנוכחית כשורש סביבת העבודה של stdlib. +stdlib.config.cwd_non_utf8 = הספרייה הנוכחית מכילה חלקים שאינם UTF-8: { $path }. + +# אבחון העוזר fetch. +stdlib.fetch.url_invalid = כתובת URL לא תקינה „{ $url }”: { $details }. +stdlib.fetch.disallowed = כתובת ה‑URL „{ $url }” אינה מותרת: { $details }. +stdlib.fetch.failed = לא ניתן היה להביא את „{ $url }”: { $details }. +stdlib.fetch.cache_read_failed = לא ניתן היה לקרוא את רשומת המטמון „{ $name }”: { $details }. +stdlib.fetch.cache_open_failed = לא ניתן היה לפתוח את רשומת המטמון „{ $name }”: { $details }. +stdlib.fetch.response_read_failed = לא ניתן היה לקרוא את התגובה מ‑„{ $url }”: { $details }. +stdlib.fetch.response_buffer_overflow = גלישת חוצץ בעת קריאת „{ $url }”. +stdlib.fetch.cache_write_failed = לא ניתן היה לכתוב את המטמון עבור „{ $url }”: { $details }. +stdlib.fetch.response_limit_exceeded = התגובה מ‑„{ $url }” חרגה ממגבלת { $limit } בתים. +stdlib.fetch.cache_limit_exceeded = התגובה שבמטמון „{ $name }” חרגה ממגבלת { $limit } בתים. +stdlib.fetch.io_failed = הפעולה „{ $action }” נכשלה עבור { $path }: { $details }. +stdlib.fetch.action.sync_cache = סנכרון מטמון fetch +stdlib.fetch.action.create_cache_dir = יצירת ספריית מטמון fetch +stdlib.fetch.action.open_cache_dir = פתיחת ספריית מטמון fetch +stdlib.fetch.action.stat_cache = קריאת נתוני רשומת מטמון fetch +stdlib.fetch.action.open_cache_entry = פתיחת רשומת מטמון fetch + +# אבחון עוזר הפקודות. +stdlib.command.location = הפקודה „{ $command }” בתבנית „{ $template }” +stdlib.command.spawn_failed = לא ניתן היה להפעיל את { $location }: { $details }. +stdlib.command.io_failed = ‏{ $location } נכשל: { $details }. +stdlib.command.closed_input_early = הקלט נסגר לפני שהכתיבה אל הפקודה הושלמה. +stdlib.command.broken_pipe = הצינור נשבר בעת הרצת { $location }: { $details }. +stdlib.command.terminated_by_signal = ‏{ $location } הופסק על ידי אות. +stdlib.command.exited_with_status = ‏{ $location } הסתיים במצב { $status }. +stdlib.command.output_limit_exceeded = ‏{ $location } חרג ממגבלת { $mode } של { $limit } בתים עבור { $stream }. +stdlib.command.timeout = ‏{ $location } חרג ממגבלת הזמן של { $seconds } שניות. +stdlib.command.exit_status_suffix = ‏(מצב יציאה { $status }) +stdlib.command.signal_suffix = ‏(הופסק על ידי אות) +stdlib.command.shell.empty = פקודת המעטפת אינה יכולה להיות ריקה. +stdlib.command.grep.empty_pattern = תבנית grep אינה יכולה להיות ריקה. +stdlib.command.grep.flags_not_string = דגלי grep חייבים להיות מחרוזות. +stdlib.command.quote.invalid = לא ניתן היה למקם את { $arg } בין מרכאות: { $details }. +stdlib.command.quote.line_break = ארגומנטים המכילים החזרת גרר או מעבר שורה אינם ניתנים למיקום בטוח בין מרכאות. +stdlib.command.input_undefined = ערך הקלט אינו מוגדר. +stdlib.command.tempfile.root_required = יצירת קובצי פקודה זמניים מחייבת את שורש סביבת העבודה. +stdlib.command.tempfile.create_failed = לא ניתן היה ליצור את קובץ הפקודה הזמני: { $details }. +stdlib.command.options.invalid_utf8 = מפתח אפשרות של פקודה חייב להיות UTF-8 תקין. +stdlib.command.option.mode_not_string = מצב הפלט חייב להיות מחרוזת. +stdlib.command.options.invalid_type = אפשרויות הפקודה חייבות להיות אובייקט. +stdlib.command.output.mode_unsupported = מצב פלט שאינו נתמך: „{ $mode }”. +stdlib.command.output.mode.capture = לכידה +stdlib.command.output.mode.streaming = הזרמה +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# אבחון עוזר הנתיבים. +stdlib.path.io.failed = הפעולה „{ $action }” נכשלה עבור { $path } ({ $label }). +stdlib.path.io.failed_with_detail = הפעולה „{ $action }” נכשלה עבור { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = הפעולה „{ $action }” נכשלה עבור { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = לא נמצא +stdlib.path.io.permission_denied = ההרשאה נדחתה +stdlib.path.io.already_exists = כבר קיים +stdlib.path.io.invalid_input = קלט לא תקין +stdlib.path.io.invalid_data = נתונים לא תקינים +stdlib.path.io.timed_out = תם הזמן +stdlib.path.io.interrupted = הופסק +stdlib.path.io.would_block = היה גורם לחסימה +stdlib.path.io.write_zero = נכתבו אפס בתים +stdlib.path.io.unexpected_eof = סוף קובץ בלתי צפוי +stdlib.path.io.broken_pipe = צינור שבור +stdlib.path.io.connection_refused = החיבור נדחה +stdlib.path.io.connection_reset = החיבור אופס +stdlib.path.io.connection_aborted = החיבור בוטל +stdlib.path.io.not_connected = אין חיבור +stdlib.path.io.addr_in_use = הכתובת בשימוש +stdlib.path.io.addr_not_available = הכתובת אינה זמינה +stdlib.path.io.out_of_memory = אין די זיכרון +stdlib.path.io.unsupported = אינו נתמך +stdlib.path.io.file_too_large = הקובץ גדול מדי +stdlib.path.io.resource_busy = המשאב תפוס +stdlib.path.io.executable_busy = קובץ ההרצה תפוס +stdlib.path.io.deadlock = קיפאון +stdlib.path.io.crosses_devices = חוצה התקנים +stdlib.path.io.too_many_links = יותר מדי קישורים +stdlib.path.io.invalid_filename = שם קובץ לא תקין +stdlib.path.io.arg_list_too_long = רשימת הארגומנטים ארוכה מדי +stdlib.path.io.stale_handle = ידית קובץ רשת מיושנת +stdlib.path.io.storage_full = שטח האחסון מלא +stdlib.path.io.not_seekable = אינו ניתן למיקום +stdlib.path.io.network_down = הרשת מושבתת +stdlib.path.io.network_unreachable = הרשת אינה נגישה +stdlib.path.io.host_unreachable = המארח אינו נגיש +stdlib.path.io.other = שגיאת קלט/פלט +stdlib.path.action.canonicalize = קנוניזציה +stdlib.path.action.open_directory = פתיחת ספרייה +stdlib.path.action.stat = קריאת נתונים +stdlib.path.action.read = קריאה +stdlib.path.action.open_file = פתיחת קובץ +stdlib.path.with_suffix.empty_separator = ‏with_suffix מחייב מפריד שאינו ריק. +stdlib.path.relative_to.mismatch = ‏{ $path } אינו יחסי אל { $root }. +stdlib.path.expanduser.unsupported = הרחבת ~ עבור משתמש מסוים אינה נתמכת. +stdlib.path.expanduser.no_home = לא ניתן להרחיב את ~: לא הוגדר אף משתנה סביבה לספריית הבית. +stdlib.path.contents.unsupported_encoding = קידוד שאינו נתמך: „{ $encoding }”. +stdlib.path.hash.unsupported_algorithm = אלגוריתם גיבוב שאינו נתמך: „{ $algorithm }”. +stdlib.path.hash.unsupported_algorithm_legacy = אלגוריתם גיבוב שאינו נתמך: „{ $algorithm }” (הפעילו את התכונה „{ $feature }”). + +# אבחון עוזרי האוספים. +stdlib.collections.flatten.expected_sequence = ‏flatten ציפה לפריטים של סדרה אך מצא { $kind }. +stdlib.collections.group_by.empty_attribute = ‏group_by מחייב תכונה שאינה ריקה. +stdlib.collections.group_by.unresolved = ‏group_by לא הצליח לאתר את „{ $attr }” בפריט מסוג { $kind }. + +# אבחון עוזרי הזמן. +stdlib.time.offset.invalid = ההיסט של now „{ $offset }” אינו תקין: נדרש „+HH:MM[:SS]” או „Z”. +stdlib.time.timedelta.overflow = גלישה ב‑timedelta בעת הוספת { $component }. +stdlib.time.label.weeks = שבועות +stdlib.time.label.days = ימים +stdlib.time.label.hours = שעות +stdlib.time.label.minutes = דקות +stdlib.time.label.seconds = שניות +stdlib.time.label.milliseconds = אלפיות שנייה +stdlib.time.label.microseconds = מיליוניות שנייה +stdlib.time.label.nanoseconds = מיליארדיות שנייה + +# אבחון העוזר which. +stdlib.which.not_found = ‏[netsuke::jinja::which::not_found] הפקודה „{ $command }” לא נמצאה לאחר בדיקת { $count } רשומות ב‑PATH. תצוגה מקדימה: { $preview } +stdlib.which.not_found.hint.cwd_auto = מקטעים ריקים ב‑PATH מתעלמים מהם; השתמשו ב‑cwd_mode="auto" כדי לכלול את ספריית העבודה. +stdlib.which.not_found.hint.cwd_always = הגדירו cwd_mode="always" כדי לכלול את הספרייה הנוכחית. +stdlib.which.direct_not_found = ‏[netsuke::jinja::which::not_found] הפקודה „{ $command }” ב‑„{ $path }” חסרה או אינה ניתנת להרצה. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = ‏<ריק> +stdlib.which.path_entry.non_utf8 = הרשומה מס׳ { $index } ב‑PATH מכילה תווים שאינם UTF-8; ‏Netsuke מחייב נתיבים בקידוד UTF-8. +stdlib.which.command.empty = ‏which מחייב מחרוזת שאינה ריקה. +stdlib.which.cwd_mode.invalid = ‏cwd_mode חייב להיות „auto”, „always” או „never”, אך התקבל „{ $mode }”. +stdlib.which.cwd.resolve_failed = לא ניתן היה לקבוע את הספרייה הנוכחית: { $details }. +stdlib.which.cwd.non_utf8 = הספרייה הנוכחית מכילה חלקים שאינם UTF-8. +stdlib.which.canonicalize_failed = לא ניתן היה לבצע קנוניזציה ל‑„{ $path }”: { $details }. +stdlib.which.is_executable = לא ניתן היה לבדוק אם „{ $path }” ניתן להרצה: { $details }. +stdlib.which.canonicalize_non_utf8 = הנתיב הקנוני מכיל חלקים שאינם UTF-8. +stdlib.which.workspace_non_utf8 = נתיב סביבת העבודה מכיל חלקים שאינם UTF-8 בעת איתור הפקודה „{ $command }”: { $path }. +stdlib.which.walkdir_error = שגיאה במעבר על סביבת העבודה בעת איתור הפקודה: { $details }. + +# רישום הספרייה התקנית. +stdlib.register.open_dir = לא ניתן היה לפתוח את הספרייה הנוכחית לצורך רישום stdlib. +stdlib.register.resolve_dir = לא ניתן היה לקבוע את הספרייה הנוכחית לצורך רישום stdlib. +stdlib.register.dir_non_utf8 = הספרייה הנוכחית מכילה חלקים שאינם UTF-8: { $path }. + +# דיווח מצב עבור מצב הפלט הנגיש. +status.state.pending = ממתין +status.state.running = מתבצע +status.state.done = הושלם +status.state.failed = נכשל +status.stage.label = שלב { $current }/{ $total }: { $description } +status.stage.summary = ‏[{ $state }] { $label } +status.stage.summary_with_task = ‏[{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = משימה { $current }/{ $total } +status.task.progress_update = ‏{ $task }: { $description } +status.stage.manifest_ingestion = קריאת קובץ המניפסט +status.stage.initial_yaml_parsing = ניתוח מסמך ה‑YAML +status.stage.template_expansion = הרחבת הנחיות התבנית +status.stage.final_rendering = ביטול הסריאליזציה ועיבוד ערכי המניפסט +status.stage.ir_generation_validation = בניית גרף התלויות ואימותו +status.stage.ninja_synthesis = הרכבת תוכנית הבנייה של Ninja +status.stage.ninja_synthesis_execute = הרכבת תוכנית Ninja והרצת { $tool } +status.stage.graph_rendering = עיבוד תוצר הגרף +status.stage.graph_rendering_with_tool = עיבוד { $tool } +status.complete = ‏הפעולה הושלמה: { $tool }. +status.timing.summary_header = סיכום זמנים לפי שלב: +status.timing.stage_line = ‏- { $label }: { $duration } +status.timing.total_line = זמן כולל של הצינור: { $duration } +status.tool.build = בנייה +status.tool.clean = ניקוי +status.tool.graph = גרף +status.tool.graph_html = גרף (HTML) +status.tool.generate = יצירה + +# מחרוזות עיבוד הגרף ל‑HTML. +graph.html.title = גרף הבנייה של Netsuke +graph.html.heading = גרף הבנייה של Netsuke +graph.html.description = גרף בנייה שעובד על ידי Netsuke +graph.html.outline.summary = יעדים ותלויות (מתאר טקסטואלי) +graph.html.outline.no_inputs = אין קלטים +graph.html.noscript.notice = ‏JavaScript מושבת. המתאר הטקסטואלי שלמעלה הוא הגרף המלא; מקור ה‑DOT מופיע אחריו. + +# קידומות סמנטיות לפלט הנגיש. +semantic.prefix.error = שגיאה: +semantic.prefix.warning = אזהרה: +semantic.prefix.success = הצלחה: +semantic.prefix.info = מידע: +semantic.prefix.timing = זמן: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# דוגמאות לצורות רבים עבור מתרגמים. +# העברית משתמשת בקטגוריות CLDR ‏`one`, ‏`two`, ‏`many` (עשרות עגולות מ‑20 +# ומעלה) ו‑`other`. +example.files_processed = { $count -> + [one] עובד קובץ אחד. + [two] עובדו שני קבצים. + [many] עובדו { $count } קבצים. + *[other] עובדו { $count } קבצים. +} + +example.errors_found = { $count -> + [0] לא נמצאו שגיאות. + [one] נמצאה שגיאה אחת. + [two] נמצאו שתי שגיאות. + [many] נמצאו { $count } שגיאות. + *[other] נמצאו { $count } שגיאות. +} diff --git a/locales/hi/messages.ftl b/locales/hi/messages.ftl new file mode 100644 index 000000000..eb6591e3f --- /dev/null +++ b/locales/hi/messages.ftl @@ -0,0 +1,400 @@ +# Netsuke की कमांड लाइन के लिए स्थानीयकरण संसाधन। + +cli.about = Netsuke YAML + Jinja मैनिफ़ेस्ट को Ninja की बिल्ड योजनाओं में संकलित करता है। +cli.long_about = Netsuke YAML + Jinja मैनिफ़ेस्ट को पुनरुत्पादनीय Ninja ग्राफ़ में बदलता है और सुरक्षित डिफ़ॉल्ट मानों के साथ Ninja चलाता है। +cli.usage = { $usage } + +# सामान्य विकल्पों का सहायता पाठ। +cli.flag.file.help = उपयोग की जाने वाली Netsuke मैनिफ़ेस्ट फ़ाइल का पथ। +cli.flag.directory.help = इस तरह चलाएँ मानो आरंभ इसी निर्देशिका में हुआ हो। +cli.flag.config.help = किसी विन्यास फ़ाइल का पथ, स्वतः खोज को छोड़ते हुए। +cli.flag.jobs.help = समांतर बिल्ड कार्यों की संख्या तय करें। +cli.flag.verbose.help = विस्तृत निदान लॉग और समाप्ति पर समय का सारांश सक्षम करें। +cli.flag.locale.help = कमांड लाइन के पाठ के लिए भाषा टैग (उदाहरण: en-US, hi)। +cli.flag.fetch_allow_scheme.help = fetch सहायक के लिए अतिरिक्त अनुमत URL स्कीम। +cli.flag.fetch_allow_host.help = डिफ़ॉल्ट अस्वीकृति सक्रिय होने पर अनुमत होस्ट नाम। +cli.flag.fetch_block_host.help = वे होस्ट नाम जो सदैव अवरुद्ध रहते हैं, भले ही अन्यत्र अनुमत हों। +cli.flag.fetch_default_deny.help = डिफ़ॉल्ट रूप से सभी होस्ट अस्वीकार करें; केवल घोषित सूची को अनुमति दें। +cli.flag.json.help = मशीन-पठनीय JSON निर्गत करें। +cli.flag.no_input.help = संवादात्मक इनपुट कभी न पढ़ें। +cli.flag.color.help = रंगीन निर्गम की नीति (auto, always, never)। +cli.flag.emoji.help = इमोजी की नीति (auto, always, never)। +cli.flag.progress.help = प्रगति दिखाने की नीति (auto, always, never)। +cli.flag.accessibility.help = सुगम्य निर्गम की नीति (auto, on, off)। +cli.flag.default_targets.help = कोई लक्ष्य न बताए जाने पर उपयोग होने वाले डिफ़ॉल्ट बिल्ड लक्ष्य। + +# उपआदेशों का विवरण। +cli.subcommand.build.about = मैनिफ़ेस्ट में परिभाषित लक्ष्यों का निर्माण करें (डिफ़ॉल्ट)। +cli.subcommand.build.long_about = माँगे गए लक्ष्यों का निर्माण करें; कोई न बताया जाए तो मैनिफ़ेस्ट के डिफ़ॉल्ट लक्ष्य लें। +cli.subcommand.clean.about = Ninja के माध्यम से बिल्ड के उत्पाद हटाएँ। +cli.subcommand.clean.long_about = एक अस्थायी Ninja फ़ाइल बनाएँ, फिर `ninja -t clean` चलाएँ। +cli.subcommand.graph.about = बिल्ड की निर्भरता ग्राफ़ निर्गत करें। डिफ़ॉल्ट प्रारूप DOT है। +cli.subcommand.graph.long_about = विश्लेषित Netsuke मैनिफ़ेस्ट को मानक बिल्ड ग्राफ़ में प्रक्षिप्त करें और उसे Graphviz DOT के रूप में लिखें, अथवा `--html` के साथ स्वतः पूर्ण HTML पृष्ठ के रूप में। फ़ाइल में लिखने हेतु `--output <फ़ाइल>` का प्रयोग करें; `-` मानक निर्गम पर लिखता है। +cli.subcommand.generate.about = Ninja चलाए बिना Ninja मैनिफ़ेस्ट बनाएँ। +cli.subcommand.generate.long_about = बनाया गया Ninja मैनिफ़ेस्ट मानक निर्गम पर लिखें, अथवा `--output` से चुनी गई फ़ाइल में। + +# build उपआदेश के विकल्पों का सहायता पाठ। +cli.subcommand.build.flag.targets.help = बनाए जाने वाले लक्ष्य (न बताए जाने पर मैनिफ़ेस्ट के डिफ़ॉल्ट लिए जाते हैं)। + +# graph उपआदेश के विकल्पों का सहायता पाठ। +cli.subcommand.graph.flag.html.help = ग्राफ़ को DOT के बजाय स्वतः पूर्ण HTML पृष्ठ के रूप में प्रस्तुत करें। +cli.subcommand.graph.flag.output.help = ग्राफ़ का उत्पाद फ़ाइल में लिखें; मानक निर्गम के लिए `-` का प्रयोग करें। + +# generate उपआदेश के विकल्पों का सहायता पाठ। +cli.subcommand.generate.flag.output.help = बनाया गया Ninja मैनिफ़ेस्ट मानक निर्गम के बजाय फ़ाइल में लिखें। + +# कमांड लाइन की सत्यापन त्रुटियाँ। +cli.validation.jobs.invalid_number = { $value } एक मान्य संख्या नहीं है। +cli.validation.jobs.out_of_range = कार्यों की संख्या { $min } और { $max } के बीच होनी चाहिए। +cli.validation.scheme.empty = स्कीम रिक्त नहीं होनी चाहिए। +cli.validation.scheme.invalid_start = स्कीम “{ $scheme }” का आरंभ ASCII अक्षर से होना चाहिए। +cli.validation.scheme.invalid = अमान्य स्कीम: “{ $scheme }”। +cli.validation.locale.empty = भाषा टैग रिक्त नहीं होना चाहिए। +cli.validation.locale.invalid = अमान्य भाषा टैग: “{ $locale }”। +cli.validation.color.invalid = अमान्य रंग नीति: “{ $value }”। मान्य विकल्प: auto, always, never। +cli.validation.emoji.invalid = अमान्य इमोजी नीति: “{ $value }”। मान्य विकल्प: auto, always, never। +cli.validation.progress.invalid = अमान्य प्रगति नीति: “{ $value }”। मान्य विकल्प: auto, always, never। +cli.validation.accessibility.invalid = अमान्य सुगम्यता नीति: “{ $value }”। मान्य विकल्प: auto, on, off। +cli.validation.config.expected_object = कमांड लाइन के मानों का क्रमांकन किसी वस्तु में होना चाहिए था, किंतु { $value } मिला। + +# Clap की त्रुटि सूचनाएँ। +clap-error-missing-argument = आवश्यक तर्क अनुपस्थित है: { $argument } +clap-error-missing-subcommand = उपआदेश अनुपस्थित है। उपलब्ध विकल्प: { $valid_subcommands } +clap-error-unknown-argument = अज्ञात तर्क: { $argument } +clap-error-invalid-value = { $argument } के लिए अमान्य मान: { $value } +clap-error-invalid-subcommand = अज्ञात उपआदेश: { $subcommand } +# ध्यान दें: value-validation का शब्दन invalid-value से भिन्न रखा गया है ताकि +# अपने सत्यापकों की विफलता (ErrorKind::ValueValidation) और प्रकार की असंगति +# (ErrorKind::InvalidValue) में अंतर बना रहे। +clap-error-value-validation = { $argument } का सत्यापन विफल रहा: { $value } + +# चलाने के दौरान की त्रुटियाँ और संदर्भ। +runner.manifest.not_found = मैनिफ़ेस्ट “{ $manifest_name }” { $directory } में नहीं मिला। +runner.manifest.not_found.help = सुनिश्चित करें कि मैनिफ़ेस्ट मौजूद है, अथवा सही पथ के साथ `--file` दें। +runner.manifest.path_missing_name = मैनिफ़ेस्ट पथ “{ $path }” में फ़ाइल नाम नहीं है। +runner.manifest.path_utf8 = मैनिफ़ेस्ट पथ “{ $path }” मान्य UTF-8 नहीं है। +runner.manifest.directory_utf8 = मैनिफ़ेस्ट की निर्देशिका का पथ “{ $path }” मान्य UTF-8 नहीं है। +runner.manifest.directory_label = निर्देशिका `{ $directory }` +runner.manifest.current_directory_label = वर्तमान निर्देशिका +runner.context.network_policy = नेटवर्क नीति नहीं बनाई जा सकी। +runner.context.load_manifest = { $path } से मैनिफ़ेस्ट नहीं लादा जा सका। +runner.context.serialise_manifest = मैनिफ़ेस्ट का क्रमांकन नहीं हो सका। +runner.context.build_graph = मैनिफ़ेस्ट से ग्राफ़ नहीं बनाया जा सका। +runner.context.generate_ninja = Ninja मैनिफ़ेस्ट नहीं बनाया जा सका। +runner.context.render_graph = ग्राफ़ का उत्पाद प्रस्तुत नहीं किया जा सका। + +runner.io.create_temp_file = अस्थायी Ninja फ़ाइल नहीं बनाई जा सकी। +runner.io.write_temp_ninja = अस्थायी Ninja फ़ाइल में नहीं लिखा जा सका। +runner.io.flush_temp_ninja = अस्थायी Ninja फ़ाइल का बफ़र खाली नहीं किया जा सका। +runner.io.sync_temp_ninja = अस्थायी Ninja फ़ाइल समकालिक नहीं की जा सकी। +runner.io.create_parent_dir = मूल निर्देशिका { $path } नहीं बनाई जा सकी। +runner.io.create_ninja_file = { $path } पर Ninja फ़ाइल नहीं बनाई जा सकी। +runner.io.write_ninja_file = { $path } की Ninja फ़ाइल में नहीं लिखा जा सका। +runner.io.flush_ninja_file = { $path } की Ninja फ़ाइल का बफ़र खाली नहीं किया जा सका। +runner.io.sync_ninja_file = { $path } की Ninja फ़ाइल समकालिक नहीं की जा सकी। +runner.io.open_ambient_dir = आसपास की निर्देशिका नहीं खोली जा सकी। +runner.io.no_existing_ancestor = { $path } के लिए कोई विद्यमान पूर्वज निर्देशिका नहीं है। +runner.io.derive_relative_path = सापेक्ष Ninja पथ नहीं निकाला जा सका। +runner.io.non_utf8_path = UTF-8 से भिन्न पथ समर्थित नहीं हैं (पथ: { $path })। +runner.io.write_stdout = Ninja मैनिफ़ेस्ट मानक निर्गम पर नहीं लिखा जा सका। +runner.io.flush_stdout = मानक निर्गम का बफ़र खाली नहीं किया जा सका। + +# मैनिफ़ेस्ट के निदान। +manifest.parse = मैनिफ़ेस्ट का विश्लेषण विफल रहा। +manifest.structure_error = { $name } पर मैनिफ़ेस्ट की संरचना में त्रुटि: { $details } +manifest.yaml.parse = पंक्ति { $line }, स्तंभ { $column } पर YAML विश्लेषण त्रुटि: { $details } +manifest.yaml.label = अमान्य YAML +manifest.yaml.hint.tabs = YAML टैब की अनुमति नहीं देता; अंतर्वेशन के लिए रिक्त स्थान लें। +manifest.yaml.hint.list_item = YAML सूची की मदें “-” से आरंभ होनी चाहिए और सही ढंग से अंतर्वेशित होनी चाहिए। +manifest.yaml.hint.expected_colon = यह प्रतिचित्रण की प्रविष्टि जान पड़ती है; कुंजी के बाद “:” नहीं है। +manifest.yaml.hint.mapping_values = YAML प्रतिचित्रणों में “:” के बाद कोई मान (अथवा नेस्टेड खंड) चाहिए। +manifest.yaml.hint.invalid_token = YAML टोकन अमान्य अथवा अप्रत्याशित है। +manifest.yaml.hint.escape = बैकस्लैश को एस्केप करें अथवा अमान्य एस्केप अनुक्रम हटाएँ। +manifest.env.missing = आवश्यक परिवेश चर “{ $name }” निर्धारित नहीं है। +manifest.env.invalid_utf8 = परिवेश चर “{ $name }” में अमान्य UTF-8 है। +manifest.vars.not_object = मैनिफ़ेस्ट का `vars` प्रतिचित्रण अथवा वस्तु होना चाहिए। +manifest.read_failed = { $path } से मैनिफ़ेस्ट नहीं पढ़ा जा सका। +manifest.resolve_workspace_root = कार्यक्षेत्र की जड़ निर्धारित नहीं की जा सकी। +manifest.workspace_non_utf8 = कार्यक्षेत्र का मूल पथ “{ $path }” मान्य UTF-8 नहीं है। +manifest.path_non_utf8 = मैनिफ़ेस्ट “{ $manifest }” का पथ मान्य UTF-8 नहीं है: { $path }। +manifest.path_missing_name = मैनिफ़ेस्ट पथ “{ $path }” में फ़ाइल नाम नहीं है। +manifest.open_workspace_failed = मैनिफ़ेस्ट { $manifest } के लिए कार्यक्षेत्र { $workspace } नहीं खोला जा सका। +manifest.foreach.not_iterable = `foreach` व्यंजक पुनरावृत्त नहीं किया जा सकता। +manifest.foreach.serialise_item = `foreach` की मद का क्रमांकन नहीं हो सका। +manifest.when.empty = `when` व्यंजक रिक्त नहीं होना चाहिए। +manifest.when.eval_error = `when` व्यंजक “{ $expr }” का मूल्यांकन नहीं हो सका। +manifest.when.template_error = `when` टेम्पलेट “{ $expr }” प्रस्तुत नहीं किया जा सका। +manifest.target.vars_not_object = लक्ष्य का `vars` वस्तु होना चाहिए, किंतु { $value } मिला। +manifest.vars.entry_not_object = मैनिफ़ेस्ट की `vars` प्रविष्टि वस्तु होनी चाहिए। +manifest.field_not_string = क्षेत्र “{ $field }” स्ट्रिंग होना चाहिए। +manifest.expression.parse_error = { $name } व्यंजक का विश्लेषण नहीं हो सका। +manifest.expression.eval_error = { $name } व्यंजक का मूल्यांकन नहीं हो सका। + +# मैनिफ़ेस्ट के मैक्रो संबंधी निदान। +manifest.macro.signature_missing_identifier = मैक्रो के हस्ताक्षर में पहचानकर्ता नहीं है। +manifest.macro.signature_missing_params = मैक्रो के हस्ताक्षर में प्राचल नहीं हैं। +manifest.macro.compile_failed = मैक्रो { $name } संकलित नहीं हो सका। +manifest.macro.sequence_invalid = मैक्रो नामों से टेम्पलेट तक के प्रतिचित्रण के रूप में परिभाषित होने चाहिए। +manifest.macro.register_failed = मैनिफ़ेस्ट के मैक्रो पंजीकृत नहीं हो सके। +manifest.macro.not_initialised = मैक्रो का परिवेश आरंभीकृत नहीं है। +manifest.macro.caller_invalid = मैक्रो का आह्वानकर्ता स्ट्रिंग होना चाहिए। +manifest.macro.template_load_failed = मैक्रो का टेम्पलेट नहीं लादा जा सका। +manifest.macro.init_failed = मैक्रो का परिवेश आरंभीकृत नहीं हो सका। +manifest.macro.missing = मैक्रो { $name } अनुपस्थित है। + +# मैनिफ़ेस्ट की glob त्रुटियाँ। +manifest.glob.unmatched_brace = अमान्य glob प्रतिरूप “{ $pattern }”: स्थान { $position } पर “{ $character }” का युग्म नहीं है। +manifest.glob.invalid_pattern = अमान्य glob प्रतिरूप “{ $pattern }”: { $detail }। +manifest.glob.unknown_pattern_error = अज्ञात प्रतिरूप त्रुटि। +manifest.glob.io_failed = “{ $pattern }” के लिए glob विफल रहा: { $detail }। +manifest.glob.unknown_io_error = अज्ञात इनपुट/आउटपुट त्रुटि। + +# मध्यवर्ती निरूपण की त्रुटियाँ। +ir.rule_not_found = लक्ष्य “{ $target }” जिस नियम “{ $rule }” का संदर्भ देता है वह नहीं मिला। +ir.multiple_rules = लक्ष्य “{ $target }” को ठीक एक नियम का संदर्भ देना चाहिए, किंतु { $rules } मिला। +ir.empty_rule = लक्ष्य “{ $target }” को किसी नियम का संदर्भ देना चाहिए। +ir.duplicate_outputs = दोहरे निर्गम मिले: { $outputs }। +ir.circular_dependency = चक्रीय निर्भरता मिली: { $cycle }। +ir.action_serialisation = क्रिया का क्रमांकन नहीं हो सका: { $details }। +ir.invalid_command = आदेश में अमान्य प्रक्षेपण: { $snippet }। + +# Ninja निर्माण की त्रुटियाँ। +ninja_gen.missing_action = किसी बिल्ड कोर द्वारा संदर्भित क्रिया “{ $id }” अनुपस्थित है। +ninja_gen.format = Ninja मैनिफ़ेस्ट का निर्गम स्वरूपित नहीं किया जा सका। + +# होस्ट प्रतिरूपों का सत्यापन। +host_pattern.empty = होस्ट प्रतिरूप रिक्त नहीं होना चाहिए। +host_pattern.contains_scheme = होस्ट प्रतिरूप “{ $pattern }” में URL स्कीम नहीं होनी चाहिए। +host_pattern.contains_slash = होस्ट प्रतिरूप “{ $pattern }” में “/” नहीं होना चाहिए। +host_pattern.missing_suffix = होस्ट प्रतिरूप “{ $pattern }” में “*.” के बाद प्रत्यय होना चाहिए। +host_pattern.empty_label = होस्ट प्रतिरूप “{ $pattern }” में रिक्त लेबल है। +host_pattern.invalid_chars = होस्ट प्रतिरूप “{ $pattern }” में अमान्य वर्ण हैं। +host_pattern.invalid_label_edge = होस्ट प्रतिरूप “{ $pattern }” के लेबल “-” से आरंभ अथवा समाप्त नहीं होने चाहिए। +host_pattern.label_too_long = होस्ट प्रतिरूप “{ $pattern }” में 63 वर्णों से लंबा लेबल है। +host_pattern.too_long = होस्ट प्रतिरूप “{ $pattern }” 255 वर्णों की सीमा से अधिक है। + +# नेटवर्क नीति। +network_policy.scheme.empty = स्कीम रिक्त नहीं होनी चाहिए। +network_policy.scheme.invalid = स्कीम “{ $scheme }” में अमान्य वर्ण हैं। +network_policy.allowlist.empty = अनुमत होस्ट की सूची रिक्त नहीं होनी चाहिए। +network_policy.scheme.not_allowed = स्कीम “{ $scheme }” अनुमत नहीं है। +network_policy.missing_host = URL में होस्ट नहीं है। +network_policy.host.blocked = होस्ट “{ $host }” नीति द्वारा अवरुद्ध है। +network_policy.host.not_allowlisted = होस्ट “{ $host }” अनुमत सूची में नहीं है। + +# मानक पुस्तकालय का विन्यास। +stdlib.config.default_fetch_cache_invalid = fetch कैश का डिफ़ॉल्ट पथ सापेक्ष होना चाहिए। +stdlib.config.default_which_cache_invalid = which कैश की डिफ़ॉल्ट क्षमता धनात्मक होनी चाहिए। +stdlib.config.workspace_root_absolute = कार्यक्षेत्र का मूल पथ निरपेक्ष होना चाहिए। +stdlib.config.fetch_response_limit_positive = fetch की अनुक्रिया सीमा धनात्मक होनी चाहिए। +stdlib.config.command_output_limit_positive = आदेश के निर्गम को संचित करने की सीमा धनात्मक होनी चाहिए। +stdlib.config.command_stream_limit_positive = आदेशों की धारा सीमा धनात्मक होनी चाहिए। +stdlib.config.which_cache_capacity_positive = which कैश की क्षमता धनात्मक होनी चाहिए। +stdlib.config.skip_dir_empty = छोड़ी जाने वाली निर्देशिकाओं की प्रविष्टियाँ रिक्त नहीं होनी चाहिए। +stdlib.config.skip_dir_navigation = छोड़ी जाने वाली निर्देशिकाओं की प्रविष्टियों में “..” नहीं होना चाहिए। +stdlib.config.skip_dir_separator = छोड़ी जाने वाली निर्देशिकाओं की प्रविष्टियों में पथ विभाजक नहीं होने चाहिए। +stdlib.config.fetch_cache_empty = fetch कैश का पथ रिक्त नहीं होना चाहिए। +stdlib.config.fetch_cache_not_relative = fetch कैश का पथ सापेक्ष होना चाहिए, किंतु { $path } मिला। +stdlib.config.fetch_cache_escapes = fetch कैश का पथ कार्यक्षेत्र से बाहर नहीं जाना चाहिए: { $path }। +stdlib.config.open_workspace_root = वर्तमान निर्देशिका को stdlib कार्यक्षेत्र की जड़ के रूप में नहीं खोला जा सका। +stdlib.config.resolve_cwd = वर्तमान निर्देशिका को stdlib कार्यक्षेत्र की जड़ के रूप में निर्धारित नहीं किया जा सका। +stdlib.config.cwd_non_utf8 = वर्तमान निर्देशिका में ऐसे अंश हैं जो UTF-8 नहीं हैं: { $path }। + +# fetch सहायक के निदान। +stdlib.fetch.url_invalid = अमान्य URL “{ $url }”: { $details }। +stdlib.fetch.disallowed = URL “{ $url }” अनुमत नहीं है: { $details }। +stdlib.fetch.failed = “{ $url }” प्राप्त नहीं किया जा सका: { $details }। +stdlib.fetch.cache_read_failed = कैश प्रविष्टि “{ $name }” नहीं पढ़ी जा सकी: { $details }। +stdlib.fetch.cache_open_failed = कैश प्रविष्टि “{ $name }” नहीं खोली जा सकी: { $details }। +stdlib.fetch.response_read_failed = “{ $url }” से अनुक्रिया नहीं पढ़ी जा सकी: { $details }। +stdlib.fetch.response_buffer_overflow = “{ $url }” पढ़ते समय बफ़र भर गया। +stdlib.fetch.cache_write_failed = “{ $url }” के लिए कैश नहीं लिखा जा सका: { $details }। +stdlib.fetch.response_limit_exceeded = “{ $url }” से आई अनुक्रिया { $limit } बाइट की सीमा से अधिक थी। +stdlib.fetch.cache_limit_exceeded = कैश में रखी अनुक्रिया “{ $name }” { $limit } बाइट की सीमा से अधिक थी। +stdlib.fetch.io_failed = { $path } पर क्रिया “{ $action }” विफल रही: { $details }। +stdlib.fetch.action.sync_cache = fetch कैश का समकालन +stdlib.fetch.action.create_cache_dir = fetch कैश निर्देशिका का निर्माण +stdlib.fetch.action.open_cache_dir = fetch कैश निर्देशिका को खोलना +stdlib.fetch.action.stat_cache = fetch कैश प्रविष्टि का विवरण पढ़ना +stdlib.fetch.action.open_cache_entry = fetch कैश प्रविष्टि को खोलना + +# आदेश सहायक के निदान। +stdlib.command.location = टेम्पलेट “{ $template }” में आदेश “{ $command }” +stdlib.command.spawn_failed = { $location } आरंभ नहीं किया जा सका: { $details }। +stdlib.command.io_failed = { $location } विफल रहा: { $details }। +stdlib.command.closed_input_early = आदेश को लिखना पूरा होने से पहले ही इनपुट बंद हो गया। +stdlib.command.broken_pipe = { $location } चलाते समय पाइप टूट गया: { $details }। +stdlib.command.terminated_by_signal = { $location } संकेत द्वारा समाप्त हुआ। +stdlib.command.exited_with_status = { $location } स्थिति { $status } के साथ समाप्त हुआ। +stdlib.command.output_limit_exceeded = { $location } ने { $stream } के लिए { $mode } की { $limit } बाइट सीमा पार कर दी। +stdlib.command.timeout = { $location } { $seconds } सेकंड की समय सीमा से आगे चला गया। +stdlib.command.exit_status_suffix = (निकास स्थिति { $status }) +stdlib.command.signal_suffix = (संकेत द्वारा समाप्त) +stdlib.command.shell.empty = शेल आदेश रिक्त नहीं होना चाहिए। +stdlib.command.grep.empty_pattern = grep का प्रतिरूप रिक्त नहीं होना चाहिए। +stdlib.command.grep.flags_not_string = grep के फ़्लैग स्ट्रिंग होने चाहिए। +stdlib.command.quote.invalid = { $arg } को उद्धरण चिह्नों में नहीं रखा जा सका: { $details }। +stdlib.command.quote.line_break = गाड़ी वापसी अथवा पंक्ति परिवर्तन वाले तर्कों को सुरक्षित रूप से उद्धृत नहीं किया जा सकता। +stdlib.command.input_undefined = इनपुट का मान अपरिभाषित है। +stdlib.command.tempfile.root_required = आदेश की अस्थायी फ़ाइलें बनाने के लिए कार्यक्षेत्र की जड़ चाहिए। +stdlib.command.tempfile.create_failed = आदेश की अस्थायी फ़ाइल नहीं बनाई जा सकी: { $details }। +stdlib.command.options.invalid_utf8 = आदेश के विकल्प की कुंजी मान्य UTF-8 होनी चाहिए। +stdlib.command.option.mode_not_string = निर्गम का ढंग स्ट्रिंग होना चाहिए। +stdlib.command.options.invalid_type = आदेश के विकल्प वस्तु होने चाहिए। +stdlib.command.output.mode_unsupported = असमर्थित निर्गम ढंग: “{ $mode }”। +stdlib.command.output.mode.capture = संचयन +stdlib.command.output.mode.streaming = धारा +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# पथ सहायक के निदान। +stdlib.path.io.failed = { $path } पर क्रिया “{ $action }” विफल रही ({ $label })। +stdlib.path.io.failed_with_detail = { $path } पर क्रिया “{ $action }” विफल रही: { $detail }। +stdlib.path.io.failed_with_label_and_detail = { $path } पर क्रिया “{ $action }” विफल रही ({ $label }): { $detail }। +stdlib.path.io.not_found = नहीं मिला +stdlib.path.io.permission_denied = अनुमति अस्वीकृत +stdlib.path.io.already_exists = पहले से विद्यमान +stdlib.path.io.invalid_input = अमान्य इनपुट +stdlib.path.io.invalid_data = अमान्य आँकड़े +stdlib.path.io.timed_out = समय समाप्त +stdlib.path.io.interrupted = बाधित +stdlib.path.io.would_block = अवरोध उत्पन्न करता +stdlib.path.io.write_zero = शून्य बाइट लिखे गए +stdlib.path.io.unexpected_eof = फ़ाइल का अप्रत्याशित अंत +stdlib.path.io.broken_pipe = टूटा हुआ पाइप +stdlib.path.io.connection_refused = संबंध अस्वीकृत +stdlib.path.io.connection_reset = संबंध पुनःस्थापित +stdlib.path.io.connection_aborted = संबंध विफल +stdlib.path.io.not_connected = संबंध नहीं है +stdlib.path.io.addr_in_use = पता पहले से प्रयोग में है +stdlib.path.io.addr_not_available = पता उपलब्ध नहीं है +stdlib.path.io.out_of_memory = स्मृति समाप्त +stdlib.path.io.unsupported = असमर्थित +stdlib.path.io.file_too_large = फ़ाइल बहुत बड़ी है +stdlib.path.io.resource_busy = संसाधन व्यस्त है +stdlib.path.io.executable_busy = निष्पादनीय फ़ाइल व्यस्त है +stdlib.path.io.deadlock = गतिरोध +stdlib.path.io.crosses_devices = उपकरणों की सीमा पार करता है +stdlib.path.io.too_many_links = बहुत अधिक कड़ियाँ +stdlib.path.io.invalid_filename = अमान्य फ़ाइल नाम +stdlib.path.io.arg_list_too_long = तर्कों की सूची बहुत लंबी है +stdlib.path.io.stale_handle = बासी नेटवर्क फ़ाइल हैंडल +stdlib.path.io.storage_full = भंडारण भर गया +stdlib.path.io.not_seekable = स्थान निर्धारण संभव नहीं +stdlib.path.io.network_down = नेटवर्क बंद है +stdlib.path.io.network_unreachable = नेटवर्क तक पहुँच नहीं +stdlib.path.io.host_unreachable = होस्ट तक पहुँच नहीं +stdlib.path.io.other = इनपुट/आउटपुट त्रुटि +stdlib.path.action.canonicalize = मानकीकरण +stdlib.path.action.open_directory = निर्देशिका खोलना +stdlib.path.action.stat = विवरण पढ़ना +stdlib.path.action.read = पढ़ना +stdlib.path.action.open_file = फ़ाइल खोलना +stdlib.path.with_suffix.empty_separator = with_suffix को अरिक्त विभाजक चाहिए। +stdlib.path.relative_to.mismatch = { $path } { $root } के सापेक्ष नहीं है। +stdlib.path.expanduser.unsupported = किसी विशेष उपयोक्ता के लिए ~ का विस्तार समर्थित नहीं है। +stdlib.path.expanduser.no_home = ~ का विस्तार नहीं हो सकता: गृह निर्देशिका का कोई परिवेश चर निर्धारित नहीं है। +stdlib.path.contents.unsupported_encoding = असमर्थित कूटलेखन: “{ $encoding }”। +stdlib.path.hash.unsupported_algorithm = असमर्थित हैश कलनविधि: “{ $algorithm }”। +stdlib.path.hash.unsupported_algorithm_legacy = असमर्थित हैश कलनविधि: “{ $algorithm }” (“{ $feature }” सुविधा सक्षम करें)। + +# संग्रह सहायकों के निदान। +stdlib.collections.flatten.expected_sequence = flatten को अनुक्रम की मदें अपेक्षित थीं, किंतु { $kind } मिला। +stdlib.collections.group_by.empty_attribute = group_by को अरिक्त गुण चाहिए। +stdlib.collections.group_by.unresolved = group_by { $kind } प्रकार की मद पर “{ $attr }” नहीं खोज सका। + +# समय सहायकों के निदान। +stdlib.time.offset.invalid = now का विचलन “{ $offset }” अमान्य है: “+HH:MM[:SS]” अथवा “Z” अपेक्षित था। +stdlib.time.timedelta.overflow = { $component } जोड़ते समय timedelta भर गया। +stdlib.time.label.weeks = सप्ताह +stdlib.time.label.days = दिन +stdlib.time.label.hours = घंटे +stdlib.time.label.minutes = मिनट +stdlib.time.label.seconds = सेकंड +stdlib.time.label.milliseconds = मिलीसेकंड +stdlib.time.label.microseconds = माइक्रोसेकंड +stdlib.time.label.nanoseconds = नैनोसेकंड + +# which सहायक के निदान। +stdlib.which.not_found = [netsuke::jinja::which::not_found] PATH की { $count } प्रविष्टियाँ जाँचने पर भी आदेश “{ $command }” नहीं मिला। झलक: { $preview } +stdlib.which.not_found.hint.cwd_auto = PATH के रिक्त खंड अनदेखे रहते हैं; कार्य निर्देशिका सम्मिलित करने हेतु cwd_mode="auto" लें। +stdlib.which.not_found.hint.cwd_always = वर्तमान निर्देशिका सम्मिलित करने हेतु cwd_mode="always" निर्धारित करें। +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] “{ $path }” पर आदेश “{ $command }” अनुपस्थित है अथवा निष्पादनीय नहीं है। +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = <रिक्त> +stdlib.which.path_entry.non_utf8 = PATH की { $index }वीं प्रविष्टि में ऐसे वर्ण हैं जो UTF-8 नहीं हैं; Netsuke को UTF-8 पथ चाहिए। +stdlib.which.command.empty = which को अरिक्त स्ट्रिंग चाहिए। +stdlib.which.cwd_mode.invalid = cwd_mode “auto”, “always” अथवा “never” होना चाहिए, किंतु “{ $mode }” मिला। +stdlib.which.cwd.resolve_failed = वर्तमान निर्देशिका निर्धारित नहीं की जा सकी: { $details }। +stdlib.which.cwd.non_utf8 = वर्तमान निर्देशिका में ऐसे अंश हैं जो UTF-8 नहीं हैं। +stdlib.which.canonicalize_failed = “{ $path }” का मानकीकरण नहीं हो सका: { $details }। +stdlib.which.is_executable = यह जाँचा नहीं जा सका कि “{ $path }” निष्पादनीय है या नहीं: { $details }। +stdlib.which.canonicalize_non_utf8 = मानक पथ में ऐसे अंश हैं जो UTF-8 नहीं हैं। +stdlib.which.workspace_non_utf8 = आदेश “{ $command }” को हल करते समय कार्यक्षेत्र के पथ में ऐसे अंश हैं जो UTF-8 नहीं हैं: { $path }। +stdlib.which.walkdir_error = आदेश हल करते समय कार्यक्षेत्र में भ्रमण के दौरान त्रुटि: { $details }। + +# मानक पुस्तकालय का पंजीकरण। +stdlib.register.open_dir = stdlib के पंजीकरण हेतु वर्तमान निर्देशिका नहीं खोली जा सकी। +stdlib.register.resolve_dir = stdlib के पंजीकरण हेतु वर्तमान निर्देशिका निर्धारित नहीं की जा सकी। +stdlib.register.dir_non_utf8 = वर्तमान निर्देशिका में ऐसे अंश हैं जो UTF-8 नहीं हैं: { $path }। + +# सुगम्य निर्गम ढंग के लिए स्थिति सूचना। +status.state.pending = प्रतीक्षारत +status.state.running = प्रगति पर +status.state.done = पूर्ण +status.state.failed = विफल +status.stage.label = चरण { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = कार्य { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = मैनिफ़ेस्ट फ़ाइल पढ़ी जा रही है +status.stage.initial_yaml_parsing = YAML दस्तावेज़ का विश्लेषण हो रहा है +status.stage.template_expansion = टेम्पलेट निर्देशों का विस्तार हो रहा है +status.stage.final_rendering = मैनिफ़ेस्ट के मानों का विक्रमांकन और प्रस्तुतीकरण हो रहा है +status.stage.ir_generation_validation = निर्भरता ग्राफ़ बनाया और जाँचा जा रहा है +status.stage.ninja_synthesis = Ninja की बिल्ड योजना बनाई जा रही है +status.stage.ninja_synthesis_execute = Ninja की योजना बनाकर { $tool } चलाया जा रहा है +status.stage.graph_rendering = ग्राफ़ का उत्पाद प्रस्तुत किया जा रहा है +status.stage.graph_rendering_with_tool = { $tool } प्रस्तुत किया जा रहा है +status.complete = { $tool }: पूर्ण। +status.timing.summary_header = चरणवार समय का सारांश: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = संपूर्ण शृंखला का कुल समय: { $duration } +status.tool.build = निर्माण +status.tool.clean = सफ़ाई +status.tool.graph = ग्राफ़ +status.tool.graph_html = ग्राफ़ (HTML) +status.tool.generate = उत्पादन + +# ग्राफ़ के HTML प्रस्तुतीकरण के पाठ। +graph.html.title = Netsuke का बिल्ड ग्राफ़ +graph.html.heading = Netsuke का बिल्ड ग्राफ़ +graph.html.description = Netsuke द्वारा प्रस्तुत बिल्ड ग्राफ़ +graph.html.outline.summary = लक्ष्य और निर्भरताएँ (पाठ रूपरेखा) +graph.html.outline.no_inputs = कोई इनपुट नहीं +graph.html.noscript.notice = JavaScript निष्क्रिय है। ऊपर की पाठ रूपरेखा ही पूरा ग्राफ़ है; उसके बाद DOT स्रोत है। + +# सुगम्य निर्गम के अर्थपूर्ण उपसर्ग। +semantic.prefix.error = त्रुटि: +semantic.prefix.warning = चेतावनी: +semantic.prefix.success = सफल: +semantic.prefix.info = सूचना: +semantic.prefix.timing = समय: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# अनुवादकों के लिए बहुवचन रूपों के उदाहरण। +# हिंदी में CLDR की दो श्रेणियाँ हैं: `one` (0 और 1 दोनों) तथा `other`। +# शून्य के लिए स्पष्ट `[0]` रूप CLDR की `one` श्रेणी से पहले चुना जाता है, +# ताकि "0 फ़ाइल" के बजाय स्वाभाविक वाक्य दिखे। +example.files_processed = { $count -> + [0] कोई फ़ाइल संसाधित नहीं हुई। + [one] { $count } फ़ाइल संसाधित हुई। + *[other] { $count } फ़ाइलें संसाधित हुईं। +} + +example.errors_found = { $count -> + [0] कोई त्रुटि नहीं मिली। + [one] { $count } त्रुटि मिली। + *[other] { $count } त्रुटियाँ मिलीं। +} diff --git a/locales/hu/messages.ftl b/locales/hu/messages.ftl new file mode 100644 index 000000000..308307a09 --- /dev/null +++ b/locales/hu/messages.ftl @@ -0,0 +1,399 @@ +# A Netsuke parancssorának honosítási erőforrásai. + +cli.about = A Netsuke YAML- és Jinja-jegyzékeket fordít Ninja-építési tervekké. +cli.long_about = A Netsuke a YAML- és Jinja-jegyzékeket reprodukálható Ninja-gráfokká alakítja, majd biztonságos alapértelmezésekkel futtatja a Ninját. +cli.usage = { $usage } + +# Az általános kapcsolók súgószövege. +cli.flag.file.help = A használandó Netsuke-jegyzékfájl elérési útja. +cli.flag.directory.help = Úgy fusson, mintha ebben a könyvtárban indult volna. +cli.flag.config.help = Egy beállításfájl elérési útja, az automatikus keresés megkerülésével. +cli.flag.jobs.help = A párhuzamos építési feladatok számának megadása. +cli.flag.verbose.help = Részletes diagnosztikai naplózás és befejezéskori időösszegzés bekapcsolása. +cli.flag.locale.help = A parancssori szövegek nyelvi címkéje (például: en-US, hu). +cli.flag.fetch_allow_scheme.help = A fetch segédfüggvény által használható további URL-sémák. +cli.flag.fetch_allow_host.help = Engedélyezett gépnevek, ha az alapértelmezett tiltás be van kapcsolva. +cli.flag.fetch_block_host.help = Mindig letiltott gépnevek, akkor is, ha máshol engedélyezettek. +cli.flag.fetch_default_deny.help = Alapértelmezés szerint minden gép tiltása; csak a megadott lista engedélyezése. +cli.flag.json.help = Géppel olvasható JSON kimenet előállítása. +cli.flag.no_input.help = Soha ne olvasson interaktív bemenetet. +cli.flag.color.help = A színes kimenet szabálya (auto, always, never). +cli.flag.emoji.help = Az emodzsik szabálya (auto, always, never). +cli.flag.progress.help = A folyamatjelzés szabálya (auto, always, never). +cli.flag.accessibility.help = Az akadálymentes kimenet szabálya (auto, on, off). +cli.flag.default_targets.help = Alapértelmezett építési célok, ha egyet sem adnak meg. + +# Az alparancsok leírása. +cli.subcommand.build.about = A jegyzékben megadott célok építése (alapértelmezett). +cli.subcommand.build.long_about = A kért célok építése; ha egyet sem adnak meg, a jegyzék alapértelmezett céljai. +cli.subcommand.clean.about = Az építési termékek eltávolítása a Ninja segítségével. +cli.subcommand.clean.long_about = Ideiglenes Ninja-fájl előállítása, majd a `ninja -t clean` futtatása. +cli.subcommand.graph.about = Az építési függőségi gráf kiírása. Az alapértelmezett formátum a DOT. +cli.subcommand.graph.long_about = A beolvasott Netsuke-jegyzék kanonikus építési gráffá alakítása és kiírása Graphviz DOT formátumban, illetve a `--html` kapcsolóval önálló HTML-oldalként. Fájlba íráshoz használja az `--output ` kapcsolót; a `-` a szabványos kimenetre ír. +cli.subcommand.generate.about = A Ninja-jegyzék előállítása a Ninja futtatása nélkül. +cli.subcommand.generate.long_about = Az előállított Ninja-jegyzék kiírása a szabványos kimenetre vagy az `--output` kapcsolóval megadott fájlba. + +# A build alparancs kapcsolóinak súgószövege. +cli.subcommand.build.flag.targets.help = Az építendő célok (elhagyásuk esetén a jegyzék alapértelmezett céljai). + +# A graph alparancs kapcsolóinak súgószövege. +cli.subcommand.graph.flag.html.help = A gráf megjelenítése önálló HTML-oldalként a DOT formátum helyett. +cli.subcommand.graph.flag.output.help = A gráftermék kiírása a FÁJLBA; a szabványos kimenethez használja a `-` jelet. + +# A generate alparancs kapcsolóinak súgószövege. +cli.subcommand.generate.flag.output.help = Az előállított Ninja-jegyzék kiírása a FÁJLBA a szabványos kimenet helyett. + +# Parancssori ellenőrzési hibák. +cli.validation.jobs.invalid_number = A(z) { $value } nem érvényes szám. +cli.validation.jobs.out_of_range = A feladatok számának { $min } és { $max } között kell lennie. +cli.validation.scheme.empty = A séma nem lehet üres. +cli.validation.scheme.invalid_start = A(z) „{ $scheme }” sémának ASCII betűvel kell kezdődnie. +cli.validation.scheme.invalid = Érvénytelen séma: „{ $scheme }”. +cli.validation.locale.empty = A nyelvi címke nem lehet üres. +cli.validation.locale.invalid = Érvénytelen nyelvi címke: „{ $locale }”. +cli.validation.color.invalid = Érvénytelen színszabály: „{ $value }”. Érvényes lehetőségek: auto, always, never. +cli.validation.emoji.invalid = Érvénytelen emodzsiszabály: „{ $value }”. Érvényes lehetőségek: auto, always, never. +cli.validation.progress.invalid = Érvénytelen folyamatszabály: „{ $value }”. Érvényes lehetőségek: auto, always, never. +cli.validation.accessibility.invalid = Érvénytelen akadálymentesítési szabály: „{ $value }”. Érvényes lehetőségek: auto, on, off. +cli.validation.config.expected_object = A parancssori értékeknek objektummá kellett volna alakulniuk, de ez érkezett: { $value }. + +# A Clap hibaüzenetei. +clap-error-missing-argument = Hiányzó kötelező argumentum: { $argument } +clap-error-missing-subcommand = Hiányzó alparancs. Elérhető lehetőségek: { $valid_subcommands } +clap-error-unknown-argument = Ismeretlen argumentum: { $argument } +clap-error-invalid-value = Érvénytelen érték ehhez: { $argument }: { $value } +clap-error-invalid-subcommand = Ismeretlen alparancs: { $subcommand } +# Megjegyzés: a value-validation megfogalmazása szándékosan eltér az +# invalid-value szövegétől, hogy elkülönüljenek a saját ellenőrzők hibái +# (ErrorKind::ValueValidation) a típuseltérésektől (ErrorKind::InvalidValue). +clap-error-value-validation = Az ellenőrzés sikertelen ehhez: { $argument }: { $value } + +# A futtatás hibái és környezete. +runner.manifest.not_found = A(z) „{ $manifest_name }” jegyzék nem található itt: { $directory }. +runner.manifest.not_found.help = Győződjön meg róla, hogy a jegyzék létezik, vagy adja meg a `--file` kapcsolót a helyes útvonallal. +runner.manifest.path_missing_name = A(z) „{ $path }” jegyzékútvonalban nincs fájlnév. +runner.manifest.path_utf8 = A(z) „{ $path }” jegyzékútvonal nem érvényes UTF-8. +runner.manifest.directory_utf8 = A jegyzék könyvtárának útvonala („{ $path }”) nem érvényes UTF-8. +runner.manifest.directory_label = a(z) `{ $directory }` könyvtár +runner.manifest.current_directory_label = az aktuális könyvtár +runner.context.network_policy = A hálózati szabályt nem sikerült felépíteni. +runner.context.load_manifest = A jegyzéket nem sikerült betölteni innen: { $path }. +runner.context.serialise_manifest = A jegyzéket nem sikerült sorosítani. +runner.context.build_graph = A gráfot nem sikerült felépíteni a jegyzékből. +runner.context.generate_ninja = A Ninja-jegyzéket nem sikerült előállítani. +runner.context.render_graph = A gráfterméket nem sikerült megjeleníteni. + +runner.io.create_temp_file = Az ideiglenes Ninja-fájlt nem sikerült létrehozni. +runner.io.write_temp_ninja = Az ideiglenes Ninja-fájlt nem sikerült megírni. +runner.io.flush_temp_ninja = Az ideiglenes Ninja-fájl pufferét nem sikerült üríteni. +runner.io.sync_temp_ninja = Az ideiglenes Ninja-fájlt nem sikerült szinkronizálni. +runner.io.create_parent_dir = A(z) { $path } szülőkönyvtárat nem sikerült létrehozni. +runner.io.create_ninja_file = A Ninja-fájlt nem sikerült létrehozni itt: { $path }. +runner.io.write_ninja_file = A Ninja-fájlt nem sikerült megírni itt: { $path }. +runner.io.flush_ninja_file = A Ninja-fájl pufferét nem sikerült üríteni itt: { $path }. +runner.io.sync_ninja_file = A Ninja-fájlt nem sikerült szinkronizálni itt: { $path }. +runner.io.open_ambient_dir = A környező könyvtárat nem sikerült megnyitni. +runner.io.no_existing_ancestor = A(z) { $path } útvonalhoz nincs létező szülőkönyvtár. +runner.io.derive_relative_path = A viszonylagos Ninja-útvonalat nem sikerült levezetni. +runner.io.non_utf8_path = A nem UTF-8 útvonalak nem támogatottak (útvonal: { $path }). +runner.io.write_stdout = A Ninja-jegyzéket nem sikerült a szabványos kimenetre írni. +runner.io.flush_stdout = A szabványos kimenet pufferét nem sikerült üríteni. + +# Jegyzékdiagnosztika. +manifest.parse = A jegyzék feldolgozása sikertelen. +manifest.structure_error = Szerkezeti hiba a jegyzékben itt: { $name }: { $details } +manifest.yaml.parse = YAML-feldolgozási hiba a(z) { $line }. sorban, { $column }. oszlopban: { $details } +manifest.yaml.label = érvénytelen YAML +manifest.yaml.hint.tabs = A YAML nem engedélyezi a tabulátorokat; a behúzáshoz használjon szóközöket. +manifest.yaml.hint.list_item = A YAML-listaelemeknek „-” jellel kell kezdődniük, és helyesen behúzottnak kell lenniük. +manifest.yaml.hint.expected_colon = Ez leképezési bejegyzésnek tűnik; a kulcs után hiányzik a „:”. +manifest.yaml.hint.mapping_values = A YAML-leképezések a „:” után értéket igényelnek (vagy beágyazott blokkot). +manifest.yaml.hint.invalid_token = A YAML-token érvénytelen vagy váratlan. +manifest.yaml.hint.escape = Escape-elje a fordított perjeleket, vagy távolítsa el az érvénytelen escape-szekvenciákat. +manifest.env.missing = A kötelező „{ $name }” környezeti változó nincs beállítva. +manifest.env.invalid_utf8 = A(z) „{ $name }” környezeti változó érvénytelen UTF-8 kódolást tartalmaz. +manifest.vars.not_object = A jegyzék `vars` mezőjének leképezésnek vagy objektumnak kell lennie. +manifest.read_failed = A jegyzéket nem sikerült beolvasni innen: { $path }. +manifest.resolve_workspace_root = A munkaterület gyökerét nem sikerült meghatározni. +manifest.workspace_non_utf8 = A munkaterület gyökérútvonala („{ $path }”) nem érvényes UTF-8. +manifest.path_non_utf8 = A(z) „{ $manifest }” jegyzék útvonala nem érvényes UTF-8: { $path }. +manifest.path_missing_name = A(z) „{ $path }” jegyzékútvonalban nincs fájlnév. +manifest.open_workspace_failed = A(z) { $workspace } munkaterületet nem sikerült megnyitni a(z) { $manifest } jegyzékhez. +manifest.foreach.not_iterable = A `foreach` kifejezés nem bejárható. +manifest.foreach.serialise_item = A `foreach` elemét nem sikerült sorosítani. +manifest.when.empty = A `when` kifejezés nem lehet üres. +manifest.when.eval_error = A(z) „{ $expr }” `when` kifejezést nem sikerült kiértékelni. +manifest.when.template_error = A(z) „{ $expr }” `when` sablont nem sikerült megjeleníteni. +manifest.target.vars_not_object = A cél `vars` mezőjének objektumnak kell lennie, de ez érkezett: { $value }. +manifest.vars.entry_not_object = A jegyzék `vars` bejegyzésének objektumnak kell lennie. +manifest.field_not_string = A(z) „{ $field }” mezőnek karakterláncnak kell lennie. +manifest.expression.parse_error = A(z) { $name } kifejezést nem sikerült feldolgozni. +manifest.expression.eval_error = A(z) { $name } kifejezést nem sikerült kiértékelni. + +# A jegyzék makróinak diagnosztikája. +manifest.macro.signature_missing_identifier = A makró fejlécéből hiányzik az azonosító. +manifest.macro.signature_missing_params = A makró fejlécéből hiányoznak a paraméterek. +manifest.macro.compile_failed = A(z) { $name } makrót nem sikerült lefordítani. +manifest.macro.sequence_invalid = A makrókat nevek és sablonok leképezéseként kell megadni. +manifest.macro.register_failed = A jegyzék makróit nem sikerült regisztrálni. +manifest.macro.not_initialised = A makrókörnyezet nincs előkészítve. +manifest.macro.caller_invalid = A makró hívójának karakterláncnak kell lennie. +manifest.macro.template_load_failed = A makró sablonját nem sikerült betölteni. +manifest.macro.init_failed = A makrókörnyezetet nem sikerült előkészíteni. +manifest.macro.missing = A(z) { $name } makró hiányzik. + +# A jegyzék glob-mintáinak hibái. +manifest.glob.unmatched_brace = Érvénytelen glob-minta („{ $pattern }”): a(z) „{ $character }” párja hiányzik a(z) { $position }. pozíción. +manifest.glob.invalid_pattern = Érvénytelen glob-minta („{ $pattern }”): { $detail }. +manifest.glob.unknown_pattern_error = ismeretlen mintahiba. +manifest.glob.io_failed = A glob sikertelen ehhez: „{ $pattern }”: { $detail }. +manifest.glob.unknown_io_error = ismeretlen be- és kiviteli hiba. + +# A köztes ábrázolás hibái. +ir.rule_not_found = A(z) „{ $target }” cél által hivatkozott „{ $rule }” szabály nem található. +ir.multiple_rules = A(z) „{ $target }” célnak pontosan egy szabályra kell hivatkoznia, de ez érkezett: { $rules }. +ir.empty_rule = A(z) „{ $target }” célnak szabályra kell hivatkoznia. +ir.duplicate_outputs = Ismétlődő kimenetek találhatók: { $outputs }. +ir.circular_dependency = Körkörös függőség található: { $cycle }. +ir.action_serialisation = A műveletet nem sikerült sorosítani: { $details }. +ir.invalid_command = Érvénytelen behelyettesítés a parancsban: { $snippet }. + +# A Ninja-fájlok előállításának hibái. +ninja_gen.missing_action = Hiányzik a(z) „{ $id }” művelet, amelyre egy építési él hivatkozik. +ninja_gen.format = A Ninja-jegyzék kimenetét nem sikerült formázni. + +# A gépminták ellenőrzése. +host_pattern.empty = A gépminta nem lehet üres. +host_pattern.contains_scheme = A(z) „{ $pattern }” gépminta nem tartalmazhat URL-sémát. +host_pattern.contains_slash = A(z) „{ $pattern }” gépminta nem tartalmazhat „/” jelet. +host_pattern.missing_suffix = A(z) „{ $pattern }” gépmintának utótagot kell tartalmaznia a „*.” után. +host_pattern.empty_label = A(z) „{ $pattern }” gépminta üres címkét tartalmaz. +host_pattern.invalid_chars = A(z) „{ $pattern }” gépminta érvénytelen karaktereket tartalmaz. +host_pattern.invalid_label_edge = A(z) „{ $pattern }” gépminta címkéi nem kezdődhetnek és nem végződhetnek „-” jellel. +host_pattern.label_too_long = A(z) „{ $pattern }” gépminta 63 karakternél hosszabb címkét tartalmaz. +host_pattern.too_long = A(z) „{ $pattern }” gépminta meghaladja a 255 karakteres korlátot. + +# Hálózati szabály. +network_policy.scheme.empty = A séma nem lehet üres. +network_policy.scheme.invalid = A(z) „{ $scheme }” séma érvénytelen karaktereket tartalmaz. +network_policy.allowlist.empty = Az engedélyezett gépek listája nem lehet üres. +network_policy.scheme.not_allowed = A(z) „{ $scheme }” séma nem engedélyezett. +network_policy.missing_host = Az URL-ből hiányzik a gép. +network_policy.host.blocked = A(z) „{ $host }” gépet a szabály letiltja. +network_policy.host.not_allowlisted = A(z) „{ $host }” gép nem szerepel az engedélyezettek listáján. + +# A szabványos programkönyvtár beállításai. +stdlib.config.default_fetch_cache_invalid = A fetch gyorsítótárának alapértelmezett útvonalának viszonylagosnak kell lennie. +stdlib.config.default_which_cache_invalid = A which gyorsítótárának alapértelmezett kapacitásának pozitívnak kell lennie. +stdlib.config.workspace_root_absolute = A munkaterület gyökérútvonalának abszolútnak kell lennie. +stdlib.config.fetch_response_limit_positive = A fetch válaszkorlátjának pozitívnak kell lennie. +stdlib.config.command_output_limit_positive = A parancskimenet rögzítési korlátjának pozitívnak kell lennie. +stdlib.config.command_stream_limit_positive = A parancsok folyamkorlátjának pozitívnak kell lennie. +stdlib.config.which_cache_capacity_positive = A which gyorsítótárának kapacitásának pozitívnak kell lennie. +stdlib.config.skip_dir_empty = A kihagyandó könyvtárak bejegyzései nem lehetnek üresek. +stdlib.config.skip_dir_navigation = A kihagyandó könyvtárak bejegyzései nem tartalmazhatnak „..” elemet. +stdlib.config.skip_dir_separator = A kihagyandó könyvtárak bejegyzései nem tartalmazhatnak útvonal-elválasztókat. +stdlib.config.fetch_cache_empty = A fetch gyorsítótárának útvonala nem lehet üres. +stdlib.config.fetch_cache_not_relative = A fetch gyorsítótárának útvonalának viszonylagosnak kell lennie, de ez érkezett: { $path }. +stdlib.config.fetch_cache_escapes = A fetch gyorsítótárának útvonala nem léphet ki a munkaterületből: { $path }. +stdlib.config.open_workspace_root = Az aktuális könyvtárat nem sikerült megnyitni a stdlib munkaterületének gyökereként. +stdlib.config.resolve_cwd = Az aktuális könyvtárat nem sikerült meghatározni a stdlib munkaterületének gyökereként. +stdlib.config.cwd_non_utf8 = Az aktuális könyvtár nem UTF-8 részeket tartalmaz: { $path }. + +# A fetch segédfüggvény diagnosztikája. +stdlib.fetch.url_invalid = Érvénytelen URL („{ $url }”): { $details }. +stdlib.fetch.disallowed = A(z) „{ $url }” URL nem engedélyezett: { $details }. +stdlib.fetch.failed = A(z) „{ $url }” letöltése sikertelen: { $details }. +stdlib.fetch.cache_read_failed = A(z) „{ $name }” gyorsítótár-bejegyzést nem sikerült beolvasni: { $details }. +stdlib.fetch.cache_open_failed = A(z) „{ $name }” gyorsítótár-bejegyzést nem sikerült megnyitni: { $details }. +stdlib.fetch.response_read_failed = A(z) „{ $url }” válaszát nem sikerült beolvasni: { $details }. +stdlib.fetch.response_buffer_overflow = Puffertúlcsordulás a(z) „{ $url }” olvasása közben. +stdlib.fetch.cache_write_failed = A(z) „{ $url }” gyorsítótárát nem sikerült megírni: { $details }. +stdlib.fetch.response_limit_exceeded = A(z) „{ $url }” válasza meghaladta a(z) { $limit } bájtos korlátot. +stdlib.fetch.cache_limit_exceeded = A gyorsítótárazott „{ $name }” válasz meghaladta a(z) { $limit } bájtos korlátot. +stdlib.fetch.io_failed = A(z) „{ $action }” művelet sikertelen ehhez: { $path }: { $details }. +stdlib.fetch.action.sync_cache = a fetch gyorsítótárának szinkronizálása +stdlib.fetch.action.create_cache_dir = a fetch gyorsítótár-könyvtárának létrehozása +stdlib.fetch.action.open_cache_dir = a fetch gyorsítótár-könyvtárának megnyitása +stdlib.fetch.action.stat_cache = a fetch gyorsítótár-bejegyzésének lekérdezése +stdlib.fetch.action.open_cache_entry = a fetch gyorsítótár-bejegyzésének megnyitása + +# A parancsokat kezelő segédfüggvény diagnosztikája. +stdlib.command.location = a(z) „{ $command }” parancs a(z) „{ $template }” sablonban +stdlib.command.spawn_failed = A(z) { $location } indítása sikertelen: { $details }. +stdlib.command.io_failed = A(z) { $location } sikertelen: { $details }. +stdlib.command.closed_input_early = A bemenet lezárult, mielőtt a parancs írása befejeződött volna. +stdlib.command.broken_pipe = Megszakadt csővezeték a(z) { $location } futtatása közben: { $details }. +stdlib.command.terminated_by_signal = A(z) { $location } futását jelzés szakította meg. +stdlib.command.exited_with_status = A(z) { $location } { $status } állapottal fejeződött be. +stdlib.command.output_limit_exceeded = A(z) { $location } túllépte a(z) { $mode } { $limit } bájtos korlátját ehhez: { $stream }. +stdlib.command.timeout = A(z) { $location } túllépte a(z) { $seconds } másodperces időkorlátot. +stdlib.command.exit_status_suffix = (kilépési állapot: { $status }) +stdlib.command.signal_suffix = (jelzés szakította meg) +stdlib.command.shell.empty = A parancsértelmezőnek szóló parancs nem lehet üres. +stdlib.command.grep.empty_pattern = A grep mintája nem lehet üres. +stdlib.command.grep.flags_not_string = A grep kapcsolóinak karakterláncnak kell lenniük. +stdlib.command.quote.invalid = A(z) { $arg } idézőjelezése sikertelen: { $details }. +stdlib.command.quote.line_break = A kocsivissza vagy soremelés karaktert tartalmazó argumentumok nem idézőjelezhetők biztonságosan. +stdlib.command.input_undefined = A bemeneti érték nincs meghatározva. +stdlib.command.tempfile.root_required = Az ideiglenes parancsfájlok létrehozásához szükség van a munkaterület gyökerére. +stdlib.command.tempfile.create_failed = Az ideiglenes parancsfájlt nem sikerült létrehozni: { $details }. +stdlib.command.options.invalid_utf8 = A parancs beállításkulcsának érvényes UTF-8 kódolásúnak kell lennie. +stdlib.command.option.mode_not_string = A kimeneti módnak karakterláncnak kell lennie. +stdlib.command.options.invalid_type = A parancs beállításainak objektumnak kell lenniük. +stdlib.command.output.mode_unsupported = Nem támogatott kimeneti mód: „{ $mode }”. +stdlib.command.output.mode.capture = rögzítés +stdlib.command.output.mode.streaming = folyamatos átvitel +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Az útvonalakat kezelő segédfüggvény diagnosztikája. +stdlib.path.io.failed = A(z) „{ $action }” művelet sikertelen ehhez: { $path } ({ $label }). +stdlib.path.io.failed_with_detail = A(z) „{ $action }” művelet sikertelen ehhez: { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = A(z) „{ $action }” művelet sikertelen ehhez: { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = nem található +stdlib.path.io.permission_denied = hozzáférés megtagadva +stdlib.path.io.already_exists = már létezik +stdlib.path.io.invalid_input = érvénytelen bemenet +stdlib.path.io.invalid_data = érvénytelen adat +stdlib.path.io.timed_out = időtúllépés +stdlib.path.io.interrupted = megszakítva +stdlib.path.io.would_block = blokkolást okozna +stdlib.path.io.write_zero = nulla bájt íródott +stdlib.path.io.unexpected_eof = váratlan fájlvég +stdlib.path.io.broken_pipe = megszakadt csővezeték +stdlib.path.io.connection_refused = a kapcsolat elutasítva +stdlib.path.io.connection_reset = a kapcsolat visszaállítva +stdlib.path.io.connection_aborted = a kapcsolat megszakítva +stdlib.path.io.not_connected = nincs kapcsolat +stdlib.path.io.addr_in_use = a cím már használatban van +stdlib.path.io.addr_not_available = a cím nem érhető el +stdlib.path.io.out_of_memory = elfogyott a memória +stdlib.path.io.unsupported = nem támogatott +stdlib.path.io.file_too_large = a fájl túl nagy +stdlib.path.io.resource_busy = az erőforrás foglalt +stdlib.path.io.executable_busy = a futtatható fájl foglalt +stdlib.path.io.deadlock = holtpont +stdlib.path.io.crosses_devices = eszközhatárt lép át +stdlib.path.io.too_many_links = túl sok hivatkozás +stdlib.path.io.invalid_filename = érvénytelen fájlnév +stdlib.path.io.arg_list_too_long = túl hosszú argumentumlista +stdlib.path.io.stale_handle = elavult hálózati fájlleíró +stdlib.path.io.storage_full = a tároló megtelt +stdlib.path.io.not_seekable = nem pozicionálható +stdlib.path.io.network_down = a hálózat nem működik +stdlib.path.io.network_unreachable = a hálózat nem érhető el +stdlib.path.io.host_unreachable = a gép nem érhető el +stdlib.path.io.other = be- és kiviteli hiba +stdlib.path.action.canonicalize = kanonizálás +stdlib.path.action.open_directory = könyvtár megnyitása +stdlib.path.action.stat = lekérdezés +stdlib.path.action.read = olvasás +stdlib.path.action.open_file = fájl megnyitása +stdlib.path.with_suffix.empty_separator = A with_suffix nem üres elválasztót igényel. +stdlib.path.relative_to.mismatch = A(z) { $path } nem viszonyítható ehhez: { $root }. +stdlib.path.expanduser.unsupported = A ~ jel adott felhasználóra vonatkozó kibontása nem támogatott. +stdlib.path.expanduser.no_home = A ~ jel nem bontható ki: nincs beállítva a saját könyvtárra vonatkozó környezeti változó. +stdlib.path.contents.unsupported_encoding = Nem támogatott kódolás: „{ $encoding }”. +stdlib.path.hash.unsupported_algorithm = Nem támogatott kivonatoló algoritmus: „{ $algorithm }”. +stdlib.path.hash.unsupported_algorithm_legacy = Nem támogatott kivonatoló algoritmus: „{ $algorithm }” (kapcsolja be a(z) „{ $feature }” szolgáltatást). + +# A gyűjteményeket kezelő segédfüggvények diagnosztikája. +stdlib.collections.flatten.expected_sequence = A flatten sorozatelemeket várt, de ezt találta: { $kind }. +stdlib.collections.group_by.empty_attribute = A group_by nem üres attribútumot igényel. +stdlib.collections.group_by.unresolved = A group_by nem találta a(z) „{ $attr }” attribútumot a(z) { $kind } típusú elemen. + +# Az időkezelő segédfüggvények diagnosztikája. +stdlib.time.offset.invalid = A now eltolása („{ $offset }”) érvénytelen: „+HH:MM[:SS]” vagy „Z” formátum szükséges. +stdlib.time.timedelta.overflow = Túlcsordulás a timedelta műveletben a(z) { $component } hozzáadásakor. +stdlib.time.label.weeks = hét +stdlib.time.label.days = nap +stdlib.time.label.hours = óra +stdlib.time.label.minutes = perc +stdlib.time.label.seconds = másodperc +stdlib.time.label.milliseconds = ezredmásodperc +stdlib.time.label.microseconds = mikromásodperc +stdlib.time.label.nanoseconds = nanomásodperc + +# A which segédfüggvény diagnosztikája. +stdlib.which.not_found = [netsuke::jinja::which::not_found] a(z) „{ $command }” parancs nem található { $count } PATH-bejegyzés ellenőrzése után. Előnézet: { $preview } +stdlib.which.not_found.hint.cwd_auto = A PATH üres szakaszait a rendszer figyelmen kívül hagyja; a munkakönyvtár bevonásához használja a cwd_mode="auto" beállítást. +stdlib.which.not_found.hint.cwd_always = Az aktuális könyvtár bevonásához állítsa be a cwd_mode="always" értéket. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] a(z) „{ $command }” parancs itt: „{ $path }” hiányzik, vagy nem futtatható. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = <üres> +stdlib.which.path_entry.non_utf8 = A(z) { $index }. PATH-bejegyzés nem UTF-8 karaktereket tartalmaz; a Netsuke UTF-8 útvonalakat igényel. +stdlib.which.command.empty = A which nem üres karakterláncot igényel. +stdlib.which.cwd_mode.invalid = A cwd_mode értéke „auto”, „always” vagy „never” lehet, de ez érkezett: „{ $mode }”. +stdlib.which.cwd.resolve_failed = Az aktuális könyvtárat nem sikerült meghatározni: { $details }. +stdlib.which.cwd.non_utf8 = Az aktuális könyvtár nem UTF-8 részeket tartalmaz. +stdlib.which.canonicalize_failed = A(z) „{ $path }” kanonizálása sikertelen: { $details }. +stdlib.which.is_executable = Nem sikerült megállapítani, hogy a(z) „{ $path }” futtatható-e: { $details }. +stdlib.which.canonicalize_non_utf8 = A kanonikus útvonal nem UTF-8 részeket tartalmaz. +stdlib.which.workspace_non_utf8 = A munkaterület útvonala nem UTF-8 részeket tartalmaz a(z) „{ $command }” parancs feloldásakor: { $path }. +stdlib.which.walkdir_error = Hiba a munkaterület bejárása közben a parancs feloldásakor: { $details }. + +# A szabványos programkönyvtár regisztrálása. +stdlib.register.open_dir = Az aktuális könyvtárat nem sikerült megnyitni a stdlib regisztrálásához. +stdlib.register.resolve_dir = Az aktuális könyvtárat nem sikerült meghatározni a stdlib regisztrálásához. +stdlib.register.dir_non_utf8 = Az aktuális könyvtár nem UTF-8 részeket tartalmaz: { $path }. + +# Állapotjelentés akadálymentes kimeneti módban. +status.state.pending = várakozik +status.state.running = folyamatban +status.state.done = kész +status.state.failed = sikertelen +status.stage.label = { $current }/{ $total }. szakasz: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = { $current }/{ $total }. feladat +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = A jegyzékfájl beolvasása +status.stage.initial_yaml_parsing = A YAML-dokumentum feldolgozása +status.stage.template_expansion = A sablondirektívák kibontása +status.stage.final_rendering = A jegyzék értékeinek visszafejtése és megjelenítése +status.stage.ir_generation_validation = A függőségi gráf felépítése és ellenőrzése +status.stage.ninja_synthesis = A Ninja-építési terv összeállítása +status.stage.ninja_synthesis_execute = A Ninja-terv összeállítása és a(z) { $tool } futtatása +status.stage.graph_rendering = A gráftermék megjelenítése +status.stage.graph_rendering_with_tool = A(z) { $tool } megjelenítése +status.complete = { $tool }: kész. +status.timing.summary_header = Szakaszonkénti időösszegzés: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = A folyamat teljes ideje: { $duration } +status.tool.build = Építés +status.tool.clean = Tisztítás +status.tool.graph = Gráf +status.tool.graph_html = Gráf (HTML) +status.tool.generate = Előállítás + +# A gráf HTML-megjelenítésének szövegei. +graph.html.title = Netsuke építési gráf +graph.html.heading = Netsuke építési gráf +graph.html.description = A Netsuke által megjelenített építési gráf +graph.html.outline.summary = Célok és függőségek (szöveges vázlat) +graph.html.outline.no_inputs = Nincs bemenet +graph.html.noscript.notice = A JavaScript ki van kapcsolva. A fenti szöveges vázlat a teljes gráfot tartalmazza; alább a DOT-forrás következik. + +# Jelentéstani előtagok az akadálymentes kimenethez. +semantic.prefix.error = Hiba: +semantic.prefix.warning = Figyelmeztetés: +semantic.prefix.success = Sikeres: +semantic.prefix.info = Tájékoztatás: +semantic.prefix.timing = Idő: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Többes számú alakok példái fordítóknak. +# A CLDR szerint a magyarnak `one` és `other` kategóriája van, de a számnév +# után a főnév egyes számban marad, ezért a két változat szövege azonos: +# „1 fájl”, „5 fájl”. +example.files_processed = { $count -> + [one] { $count } fájl feldolgozva. + *[other] { $count } fájl feldolgozva. +} + +example.errors_found = { $count -> + [0] Nem található hiba. + [one] { $count } hiba található. + *[other] { $count } hiba található. +} diff --git a/locales/id/messages.ftl b/locales/id/messages.ftl new file mode 100644 index 000000000..88faf5660 --- /dev/null +++ b/locales/id/messages.ftl @@ -0,0 +1,396 @@ +# Sumber daya pelokalan untuk antarmuka baris perintah Netsuke. + +cli.about = Netsuke mengompilasi manifes YAML + Jinja menjadi rencana build Ninja. +cli.long_about = Netsuke mengubah manifes YAML + Jinja menjadi graf Ninja yang dapat direproduksi dan menjalankan Ninja dengan nilai bawaan yang aman. +cli.usage = { $usage } + +# Teks bantuan untuk opsi umum. +cli.flag.file.help = Jalur berkas manifes Netsuke yang akan digunakan. +cli.flag.directory.help = Jalankan seolah-olah dimulai di direktori ini. +cli.flag.config.help = Jalur berkas konfigurasi, melewati pencarian otomatis. +cli.flag.jobs.help = Tetapkan jumlah tugas build paralel. +cli.flag.verbose.help = Aktifkan pencatatan diagnostik terperinci dan ringkasan waktu saat selesai. +cli.flag.locale.help = Tag bahasa untuk teks baris perintah (misalnya: en-US, id). +cli.flag.fetch_allow_scheme.help = Skema URL tambahan yang diizinkan bagi pembantu fetch. +cli.flag.fetch_allow_host.help = Nama host yang diizinkan ketika penolakan bawaan aktif. +cli.flag.fetch_block_host.help = Nama host yang selalu diblokir, meski diizinkan di tempat lain. +cli.flag.fetch_default_deny.help = Tolak semua host secara bawaan; izinkan hanya daftar yang dinyatakan. +cli.flag.json.help = Hasilkan keluaran JSON yang terbaca mesin. +cli.flag.no_input.help = Jangan pernah membaca masukan interaktif. +cli.flag.color.help = Kebijakan keluaran berwarna (auto, always, never). +cli.flag.emoji.help = Kebijakan emoji (auto, always, never). +cli.flag.progress.help = Kebijakan tampilan kemajuan (auto, always, never). +cli.flag.accessibility.help = Kebijakan keluaran yang mudah diakses (auto, on, off). +cli.flag.default_targets.help = Target build bawaan ketika tidak ada yang ditentukan. + +# Deskripsi subperintah. +cli.subcommand.build.about = Bangun target yang ditetapkan dalam manifes (bawaan). +cli.subcommand.build.long_about = Bangun target yang diminta; bila tidak ada, gunakan target bawaan dari manifes. +cli.subcommand.clean.about = Hapus artefak build melalui Ninja. +cli.subcommand.clean.long_about = Hasilkan berkas Ninja sementara, lalu jalankan `ninja -t clean`. +cli.subcommand.graph.about = Keluarkan graf ketergantungan build. Format bawaannya adalah DOT. +cli.subcommand.graph.long_about = Proyeksikan manifes Netsuke yang telah diurai menjadi graf build kanonis dan tulis sebagai Graphviz DOT, atau sebagai halaman HTML mandiri dengan `--html`. Gunakan `--output ` untuk menulis ke berkas; `-` menulis ke keluaran standar. +cli.subcommand.generate.about = Hasilkan manifes Ninja tanpa menjalankan Ninja. +cli.subcommand.generate.long_about = Tulis manifes Ninja yang dihasilkan ke keluaran standar atau ke berkas yang dipilih dengan `--output`. + +# Teks bantuan untuk opsi subperintah build. +cli.subcommand.build.flag.targets.help = Target yang akan dibangun (jika dihilangkan, memakai bawaan dari manifes). + +# Teks bantuan untuk opsi subperintah graph. +cli.subcommand.graph.flag.html.help = Render graf sebagai halaman HTML mandiri alih-alih DOT. +cli.subcommand.graph.flag.output.help = Tulis artefak graf ke BERKAS; gunakan `-` untuk keluaran standar. + +# Teks bantuan untuk opsi subperintah generate. +cli.subcommand.generate.flag.output.help = Tulis manifes Ninja yang dihasilkan ke BERKAS alih-alih keluaran standar. + +# Galat validasi baris perintah. +cli.validation.jobs.invalid_number = { $value } bukan angka yang sah. +cli.validation.jobs.out_of_range = Jumlah tugas harus berada di antara { $min } dan { $max }. +cli.validation.scheme.empty = Skema tidak boleh kosong. +cli.validation.scheme.invalid_start = Skema "{ $scheme }" harus diawali huruf ASCII. +cli.validation.scheme.invalid = Skema tidak sah: "{ $scheme }". +cli.validation.locale.empty = Tag bahasa tidak boleh kosong. +cli.validation.locale.invalid = Tag bahasa tidak sah: "{ $locale }". +cli.validation.color.invalid = Kebijakan warna tidak sah: "{ $value }". Pilihan yang sah: auto, always, never. +cli.validation.emoji.invalid = Kebijakan emoji tidak sah: "{ $value }". Pilihan yang sah: auto, always, never. +cli.validation.progress.invalid = Kebijakan kemajuan tidak sah: "{ $value }". Pilihan yang sah: auto, always, never. +cli.validation.accessibility.invalid = Kebijakan aksesibilitas tidak sah: "{ $value }". Pilihan yang sah: auto, on, off. +cli.validation.config.expected_object = Nilai baris perintah seharusnya diserialkan menjadi objek, tetapi diperoleh { $value }. + +# Pesan galat dari Clap. +clap-error-missing-argument = Argumen wajib tidak ada: { $argument } +clap-error-missing-subcommand = Subperintah tidak ada. Pilihan yang tersedia: { $valid_subcommands } +clap-error-unknown-argument = Argumen tidak dikenal: { $argument } +clap-error-invalid-value = Nilai tidak sah untuk { $argument }: { $value } +clap-error-invalid-subcommand = Subperintah tidak dikenal: { $subcommand } +# Catatan: value-validation dirumuskan berbeda dari invalid-value agar galat +# validator khusus (ErrorKind::ValueValidation) terbedakan dari ketidakcocokan +# tipe (ErrorKind::InvalidValue). +clap-error-value-validation = Validasi gagal untuk { $argument }: { $value } + +# Galat dan konteks saat berjalan. +runner.manifest.not_found = Manifes "{ $manifest_name }" tidak ditemukan di { $directory }. +runner.manifest.not_found.help = Pastikan manifes ada, atau berikan `--file` dengan jalur yang benar. +runner.manifest.path_missing_name = Jalur manifes "{ $path }" tidak memuat nama berkas. +runner.manifest.path_utf8 = Jalur manifes "{ $path }" bukan UTF-8 yang sah. +runner.manifest.directory_utf8 = Jalur direktori manifes "{ $path }" bukan UTF-8 yang sah. +runner.manifest.directory_label = direktori `{ $directory }` +runner.manifest.current_directory_label = direktori saat ini +runner.context.network_policy = Kebijakan jaringan tidak dapat dibangun. +runner.context.load_manifest = Manifes di { $path } tidak dapat dimuat. +runner.context.serialise_manifest = Manifes tidak dapat diserialkan. +runner.context.build_graph = Graf tidak dapat dibangun dari manifes. +runner.context.generate_ninja = Manifes Ninja tidak dapat dihasilkan. +runner.context.render_graph = Artefak graf tidak dapat dirender. + +runner.io.create_temp_file = Berkas Ninja sementara tidak dapat dibuat. +runner.io.write_temp_ninja = Berkas Ninja sementara tidak dapat ditulis. +runner.io.flush_temp_ninja = Penyangga berkas Ninja sementara tidak dapat dikosongkan. +runner.io.sync_temp_ninja = Berkas Ninja sementara tidak dapat disinkronkan. +runner.io.create_parent_dir = Direktori induk { $path } tidak dapat dibuat. +runner.io.create_ninja_file = Berkas Ninja di { $path } tidak dapat dibuat. +runner.io.write_ninja_file = Berkas Ninja di { $path } tidak dapat ditulis. +runner.io.flush_ninja_file = Penyangga berkas Ninja di { $path } tidak dapat dikosongkan. +runner.io.sync_ninja_file = Berkas Ninja di { $path } tidak dapat disinkronkan. +runner.io.open_ambient_dir = Direktori sekitar tidak dapat dibuka. +runner.io.no_existing_ancestor = Tidak ada direktori induk yang ada untuk { $path }. +runner.io.derive_relative_path = Jalur Ninja relatif tidak dapat diturunkan. +runner.io.non_utf8_path = Jalur yang bukan UTF-8 tidak didukung (jalur: { $path }). +runner.io.write_stdout = Manifes Ninja tidak dapat ditulis ke keluaran standar. +runner.io.flush_stdout = Penyangga keluaran standar tidak dapat dikosongkan. + +# Diagnostik manifes. +manifest.parse = Penguraian manifes gagal. +manifest.structure_error = Galat struktur manifes pada { $name }: { $details } +manifest.yaml.parse = Galat penguraian YAML pada baris { $line }, kolom { $column }: { $details } +manifest.yaml.label = YAML tidak sah +manifest.yaml.hint.tabs = YAML tidak mengizinkan tab; gunakan spasi untuk indentasi. +manifest.yaml.hint.list_item = Butir daftar YAML harus diawali "-" dan diindentasi dengan benar. +manifest.yaml.hint.expected_colon = Ini tampak seperti entri pemetaan; ":" hilang setelah kunci. +manifest.yaml.hint.mapping_values = Pemetaan YAML memerlukan nilai setelah ":" (atau blok bersarang). +manifest.yaml.hint.invalid_token = Token YAML tidak sah atau tidak terduga. +manifest.yaml.hint.escape = Lakukan escape pada garis miring terbalik atau hapus urutan pelolosan yang tidak sah. +manifest.env.missing = Variabel lingkungan wajib "{ $name }" belum disetel. +manifest.env.invalid_utf8 = Variabel lingkungan "{ $name }" memuat UTF-8 yang tidak sah. +manifest.vars.not_object = `vars` pada manifes harus berupa pemetaan atau objek. +manifest.read_failed = Manifes di { $path } tidak dapat dibaca. +manifest.resolve_workspace_root = Akar ruang kerja tidak dapat ditentukan. +manifest.workspace_non_utf8 = Jalur akar ruang kerja "{ $path }" bukan UTF-8 yang sah. +manifest.path_non_utf8 = Jalur manifes "{ $manifest }" bukan UTF-8 yang sah: { $path }. +manifest.path_missing_name = Jalur manifes "{ $path }" tidak memuat nama berkas. +manifest.open_workspace_failed = Ruang kerja { $workspace } tidak dapat dibuka untuk manifes { $manifest }. +manifest.foreach.not_iterable = Ekspresi `foreach` tidak dapat diiterasi. +manifest.foreach.serialise_item = Butir `foreach` tidak dapat diserialkan. +manifest.when.empty = Ekspresi `when` tidak boleh kosong. +manifest.when.eval_error = Ekspresi `when` "{ $expr }" tidak dapat dievaluasi. +manifest.when.template_error = Templat `when` "{ $expr }" tidak dapat dirender. +manifest.target.vars_not_object = `vars` pada target harus berupa objek, tetapi diperoleh { $value }. +manifest.vars.entry_not_object = Entri `vars` pada manifes harus berupa objek. +manifest.field_not_string = Ruas "{ $field }" harus berupa untai. +manifest.expression.parse_error = Ekspresi { $name } tidak dapat diurai. +manifest.expression.eval_error = Ekspresi { $name } tidak dapat dievaluasi. + +# Diagnostik makro manifes. +manifest.macro.signature_missing_identifier = Tanda tangan makro tidak memuat pengenal. +manifest.macro.signature_missing_params = Tanda tangan makro tidak memuat parameter. +manifest.macro.compile_failed = Makro { $name } tidak dapat dikompilasi. +manifest.macro.sequence_invalid = Makro harus ditetapkan sebagai pemetaan nama ke templat. +manifest.macro.register_failed = Makro manifes tidak dapat didaftarkan. +manifest.macro.not_initialised = Lingkungan makro belum disiapkan. +manifest.macro.caller_invalid = Pemanggil makro harus berupa untai. +manifest.macro.template_load_failed = Templat makro tidak dapat dimuat. +manifest.macro.init_failed = Lingkungan makro tidak dapat disiapkan. +manifest.macro.missing = Makro { $name } tidak ada. + +# Galat pola glob pada manifes. +manifest.glob.unmatched_brace = Pola glob tidak sah "{ $pattern }": "{ $character }" tanpa pasangan pada posisi { $position }. +manifest.glob.invalid_pattern = Pola glob tidak sah "{ $pattern }": { $detail }. +manifest.glob.unknown_pattern_error = galat pola yang tidak dikenal. +manifest.glob.io_failed = Glob gagal untuk "{ $pattern }": { $detail }. +manifest.glob.unknown_io_error = galat masukan/keluaran yang tidak dikenal. + +# Galat representasi antara. +ir.rule_not_found = Aturan "{ $rule }" yang dirujuk target "{ $target }" tidak ditemukan. +ir.multiple_rules = Target "{ $target }" harus merujuk tepat satu aturan, tetapi diperoleh { $rules }. +ir.empty_rule = Target "{ $target }" harus merujuk sebuah aturan. +ir.duplicate_outputs = Terdeteksi keluaran ganda: { $outputs }. +ir.circular_dependency = Terdeteksi ketergantungan melingkar: { $cycle }. +ir.action_serialisation = Tindakan tidak dapat diserialkan: { $details }. +ir.invalid_command = Penyisipan tidak sah pada perintah: { $snippet }. + +# Galat pembuatan berkas Ninja. +ninja_gen.missing_action = Tindakan "{ $id }" yang dirujuk sebuah sisi build tidak ada. +ninja_gen.format = Keluaran manifes Ninja tidak dapat diformat. + +# Validasi pola host. +host_pattern.empty = Pola host tidak boleh kosong. +host_pattern.contains_scheme = Pola host "{ $pattern }" tidak boleh memuat skema URL. +host_pattern.contains_slash = Pola host "{ $pattern }" tidak boleh memuat "/". +host_pattern.missing_suffix = Pola host "{ $pattern }" harus memuat akhiran setelah "*.". +host_pattern.empty_label = Pola host "{ $pattern }" memuat label kosong. +host_pattern.invalid_chars = Pola host "{ $pattern }" memuat karakter yang tidak sah. +host_pattern.invalid_label_edge = Label pada pola host "{ $pattern }" tidak boleh diawali atau diakhiri "-". +host_pattern.label_too_long = Pola host "{ $pattern }" memuat label yang lebih panjang dari 63 karakter. +host_pattern.too_long = Pola host "{ $pattern }" melampaui batas 255 karakter. + +# Kebijakan jaringan. +network_policy.scheme.empty = Skema tidak boleh kosong. +network_policy.scheme.invalid = Skema "{ $scheme }" memuat karakter yang tidak sah. +network_policy.allowlist.empty = Daftar host yang diizinkan tidak boleh kosong. +network_policy.scheme.not_allowed = Skema "{ $scheme }" tidak diizinkan. +network_policy.missing_host = URL tidak memuat host. +network_policy.host.blocked = Host "{ $host }" diblokir oleh kebijakan. +network_policy.host.not_allowlisted = Host "{ $host }" tidak ada dalam daftar yang diizinkan. + +# Konfigurasi pustaka standar. +stdlib.config.default_fetch_cache_invalid = Jalur bawaan singgahan fetch harus relatif. +stdlib.config.default_which_cache_invalid = Kapasitas bawaan singgahan which harus positif. +stdlib.config.workspace_root_absolute = Jalur akar ruang kerja harus absolut. +stdlib.config.fetch_response_limit_positive = Batas tanggapan fetch harus positif. +stdlib.config.command_output_limit_positive = Batas penangkapan keluaran perintah harus positif. +stdlib.config.command_stream_limit_positive = Batas aliran perintah harus positif. +stdlib.config.which_cache_capacity_positive = Kapasitas singgahan which harus positif. +stdlib.config.skip_dir_empty = Entri direktori yang dilewati tidak boleh kosong. +stdlib.config.skip_dir_navigation = Entri direktori yang dilewati tidak boleh memuat "..". +stdlib.config.skip_dir_separator = Entri direktori yang dilewati tidak boleh memuat pemisah jalur. +stdlib.config.fetch_cache_empty = Jalur singgahan fetch tidak boleh kosong. +stdlib.config.fetch_cache_not_relative = Jalur singgahan fetch harus relatif, tetapi diperoleh { $path }. +stdlib.config.fetch_cache_escapes = Jalur singgahan fetch tidak boleh keluar dari ruang kerja: { $path }. +stdlib.config.open_workspace_root = Direktori saat ini tidak dapat dibuka sebagai akar ruang kerja stdlib. +stdlib.config.resolve_cwd = Direktori saat ini tidak dapat ditentukan sebagai akar ruang kerja stdlib. +stdlib.config.cwd_non_utf8 = Direktori saat ini memuat bagian yang bukan UTF-8: { $path }. + +# Diagnostik pembantu fetch. +stdlib.fetch.url_invalid = URL tidak sah "{ $url }": { $details }. +stdlib.fetch.disallowed = URL "{ $url }" tidak diizinkan: { $details }. +stdlib.fetch.failed = Gagal mengambil "{ $url }": { $details }. +stdlib.fetch.cache_read_failed = Entri singgahan "{ $name }" tidak dapat dibaca: { $details }. +stdlib.fetch.cache_open_failed = Entri singgahan "{ $name }" tidak dapat dibuka: { $details }. +stdlib.fetch.response_read_failed = Tanggapan dari "{ $url }" tidak dapat dibaca: { $details }. +stdlib.fetch.response_buffer_overflow = Penyangga meluap saat membaca "{ $url }". +stdlib.fetch.cache_write_failed = Singgahan untuk "{ $url }" tidak dapat ditulis: { $details }. +stdlib.fetch.response_limit_exceeded = Tanggapan dari "{ $url }" melampaui batas { $limit } bita. +stdlib.fetch.cache_limit_exceeded = Tanggapan tersinggah "{ $name }" melampaui batas { $limit } bita. +stdlib.fetch.io_failed = Tindakan "{ $action }" gagal untuk { $path }: { $details }. +stdlib.fetch.action.sync_cache = menyinkronkan singgahan fetch +stdlib.fetch.action.create_cache_dir = membuat direktori singgahan fetch +stdlib.fetch.action.open_cache_dir = membuka direktori singgahan fetch +stdlib.fetch.action.stat_cache = membaca keterangan entri singgahan fetch +stdlib.fetch.action.open_cache_entry = membuka entri singgahan fetch + +# Diagnostik pembantu perintah. +stdlib.command.location = perintah "{ $command }" dalam templat "{ $template }" +stdlib.command.spawn_failed = { $location } tidak dapat dijalankan: { $details }. +stdlib.command.io_failed = { $location } gagal: { $details }. +stdlib.command.closed_input_early = Masukan tertutup sebelum penulisan ke perintah selesai. +stdlib.command.broken_pipe = Pipa terputus saat menjalankan { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } dihentikan oleh sinyal. +stdlib.command.exited_with_status = { $location } berakhir dengan status { $status }. +stdlib.command.output_limit_exceeded = { $location } melampaui batas { $mode } sebesar { $limit } bita untuk { $stream }. +stdlib.command.timeout = { $location } melampaui batas waktu { $seconds } detik. +stdlib.command.exit_status_suffix = (status keluar { $status }) +stdlib.command.signal_suffix = (dihentikan oleh sinyal) +stdlib.command.shell.empty = Perintah shell tidak boleh kosong. +stdlib.command.grep.empty_pattern = Pola grep tidak boleh kosong. +stdlib.command.grep.flags_not_string = Bendera grep harus berupa untai. +stdlib.command.quote.invalid = { $arg } tidak dapat diberi tanda kutip: { $details }. +stdlib.command.quote.line_break = Argumen yang memuat retur kereta atau ganti baris tidak dapat diberi tanda kutip dengan aman. +stdlib.command.input_undefined = Nilai masukan tidak terdefinisi. +stdlib.command.tempfile.root_required = Akar ruang kerja diperlukan untuk membuat berkas perintah sementara. +stdlib.command.tempfile.create_failed = Berkas perintah sementara tidak dapat dibuat: { $details }. +stdlib.command.options.invalid_utf8 = Kunci opsi perintah harus berupa UTF-8 yang sah. +stdlib.command.option.mode_not_string = Mode keluaran harus berupa untai. +stdlib.command.options.invalid_type = Opsi perintah harus berupa objek. +stdlib.command.output.mode_unsupported = Mode keluaran tidak didukung: "{ $mode }". +stdlib.command.output.mode.capture = penangkapan +stdlib.command.output.mode.streaming = penstriman +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Diagnostik pembantu jalur. +stdlib.path.io.failed = Tindakan "{ $action }" gagal untuk { $path } ({ $label }). +stdlib.path.io.failed_with_detail = Tindakan "{ $action }" gagal untuk { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = Tindakan "{ $action }" gagal untuk { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = tidak ditemukan +stdlib.path.io.permission_denied = akses ditolak +stdlib.path.io.already_exists = sudah ada +stdlib.path.io.invalid_input = masukan tidak sah +stdlib.path.io.invalid_data = data tidak sah +stdlib.path.io.timed_out = waktu habis +stdlib.path.io.interrupted = terputus +stdlib.path.io.would_block = akan memblokir +stdlib.path.io.write_zero = nol bita tertulis +stdlib.path.io.unexpected_eof = akhir berkas tak terduga +stdlib.path.io.broken_pipe = pipa terputus +stdlib.path.io.connection_refused = koneksi ditolak +stdlib.path.io.connection_reset = koneksi disetel ulang +stdlib.path.io.connection_aborted = koneksi dibatalkan +stdlib.path.io.not_connected = tidak terhubung +stdlib.path.io.addr_in_use = alamat sedang dipakai +stdlib.path.io.addr_not_available = alamat tidak tersedia +stdlib.path.io.out_of_memory = memori habis +stdlib.path.io.unsupported = tidak didukung +stdlib.path.io.file_too_large = berkas terlalu besar +stdlib.path.io.resource_busy = sumber daya sibuk +stdlib.path.io.executable_busy = berkas eksekusi sibuk +stdlib.path.io.deadlock = kebuntuan +stdlib.path.io.crosses_devices = melintasi perangkat +stdlib.path.io.too_many_links = terlalu banyak tautan +stdlib.path.io.invalid_filename = nama berkas tidak sah +stdlib.path.io.arg_list_too_long = daftar argumen terlalu panjang +stdlib.path.io.stale_handle = tangkai berkas jaringan usang +stdlib.path.io.storage_full = penyimpanan penuh +stdlib.path.io.not_seekable = tidak dapat diposisikan +stdlib.path.io.network_down = jaringan mati +stdlib.path.io.network_unreachable = jaringan tak terjangkau +stdlib.path.io.host_unreachable = host tak terjangkau +stdlib.path.io.other = galat masukan/keluaran +stdlib.path.action.canonicalize = kanonikalisasi +stdlib.path.action.open_directory = membuka direktori +stdlib.path.action.stat = membaca keterangan +stdlib.path.action.read = membaca +stdlib.path.action.open_file = membuka berkas +stdlib.path.with_suffix.empty_separator = with_suffix memerlukan pemisah yang tidak kosong. +stdlib.path.relative_to.mismatch = { $path } tidak relatif terhadap { $root }. +stdlib.path.expanduser.unsupported = Ekspansi ~ untuk pengguna tertentu tidak didukung. +stdlib.path.expanduser.no_home = ~ tidak dapat diekspansi: tidak ada variabel lingkungan direktori beranda yang disetel. +stdlib.path.contents.unsupported_encoding = Pengodean tidak didukung: "{ $encoding }". +stdlib.path.hash.unsupported_algorithm = Algoritme hash tidak didukung: "{ $algorithm }". +stdlib.path.hash.unsupported_algorithm_legacy = Algoritme hash tidak didukung: "{ $algorithm }" (aktifkan fitur "{ $feature }"). + +# Diagnostik pembantu koleksi. +stdlib.collections.flatten.expected_sequence = flatten mengharapkan butir urutan tetapi menemukan { $kind }. +stdlib.collections.group_by.empty_attribute = group_by memerlukan atribut yang tidak kosong. +stdlib.collections.group_by.unresolved = group_by tidak dapat menemukan "{ $attr }" pada butir bertipe { $kind }. + +# Diagnostik pembantu waktu. +stdlib.time.offset.invalid = Ofset now "{ $offset }" tidak sah: diharapkan "+HH:MM[:SS]" atau "Z". +stdlib.time.timedelta.overflow = timedelta meluap saat menambahkan { $component }. +stdlib.time.label.weeks = minggu +stdlib.time.label.days = hari +stdlib.time.label.hours = jam +stdlib.time.label.minutes = menit +stdlib.time.label.seconds = detik +stdlib.time.label.milliseconds = milidetik +stdlib.time.label.microseconds = mikrodetik +stdlib.time.label.nanoseconds = nanodetik + +# Diagnostik pembantu which. +stdlib.which.not_found = [netsuke::jinja::which::not_found] perintah "{ $command }" tidak ditemukan setelah memeriksa { $count } entri PATH. Pratinjau: { $preview } +stdlib.which.not_found.hint.cwd_auto = Ruas PATH yang kosong diabaikan; gunakan cwd_mode="auto" untuk menyertakan direktori kerja. +stdlib.which.not_found.hint.cwd_always = Setel cwd_mode="always" untuk menyertakan direktori saat ini. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] perintah "{ $command }" di "{ $path }" tidak ada atau tidak dapat dieksekusi. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = Entri PATH ke-{ $index } memuat karakter yang bukan UTF-8; Netsuke memerlukan jalur UTF-8. +stdlib.which.command.empty = which memerlukan untai yang tidak kosong. +stdlib.which.cwd_mode.invalid = cwd_mode harus "auto", "always", atau "never", tetapi diperoleh "{ $mode }". +stdlib.which.cwd.resolve_failed = Direktori saat ini tidak dapat ditentukan: { $details }. +stdlib.which.cwd.non_utf8 = Direktori saat ini memuat bagian yang bukan UTF-8. +stdlib.which.canonicalize_failed = "{ $path }" tidak dapat dikanonikalisasi: { $details }. +stdlib.which.is_executable = Tidak dapat memastikan apakah "{ $path }" dapat dieksekusi: { $details }. +stdlib.which.canonicalize_non_utf8 = Jalur kanonis memuat bagian yang bukan UTF-8. +stdlib.which.workspace_non_utf8 = Jalur ruang kerja memuat bagian yang bukan UTF-8 saat menyelesaikan perintah "{ $command }": { $path }. +stdlib.which.walkdir_error = Galat saat menelusuri ruang kerja ketika menyelesaikan perintah: { $details }. + +# Pendaftaran pustaka standar. +stdlib.register.open_dir = Direktori saat ini tidak dapat dibuka untuk pendaftaran stdlib. +stdlib.register.resolve_dir = Direktori saat ini tidak dapat ditentukan untuk pendaftaran stdlib. +stdlib.register.dir_non_utf8 = Direktori saat ini memuat bagian yang bukan UTF-8: { $path }. + +# Pelaporan status untuk mode keluaran yang mudah diakses. +status.state.pending = menunggu +status.state.running = sedang berjalan +status.state.done = selesai +status.state.failed = gagal +status.stage.label = Tahap { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Tugas { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Membaca berkas manifes +status.stage.initial_yaml_parsing = Mengurai dokumen YAML +status.stage.template_expansion = Mengembangkan arahan templat +status.stage.final_rendering = Mendeserialkan dan merender nilai manifes +status.stage.ir_generation_validation = Membangun dan memvalidasi graf ketergantungan +status.stage.ninja_synthesis = Menyusun rencana build Ninja +status.stage.ninja_synthesis_execute = Menyusun rencana Ninja dan menjalankan { $tool } +status.stage.graph_rendering = Merender artefak graf +status.stage.graph_rendering_with_tool = Merender { $tool } +status.complete = { $tool } selesai. +status.timing.summary_header = Ringkasan waktu per tahap: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Total waktu alur: { $duration } +status.tool.build = Build +status.tool.clean = Pembersihan +status.tool.graph = Graf +status.tool.graph_html = Graf (HTML) +status.tool.generate = Pembuatan + +# Teks perender HTML untuk graf. +graph.html.title = Graf build Netsuke +graph.html.heading = Graf build Netsuke +graph.html.description = Graf build yang dirender oleh Netsuke +graph.html.outline.summary = Target dan ketergantungan (kerangka teks) +graph.html.outline.no_inputs = Tidak ada masukan +graph.html.noscript.notice = JavaScript dinonaktifkan. Kerangka teks di atas memuat seluruh graf; sumber DOT menyusul di bawah. + +# Awalan semantik untuk keluaran yang mudah diakses. +semantic.prefix.error = Galat: +semantic.prefix.warning = Peringatan: +semantic.prefix.success = Berhasil: +semantic.prefix.info = Info: +semantic.prefix.timing = Waktu: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Contoh bentuk jamak untuk penerjemah. +# Bahasa Indonesia hanya memakai kategori CLDR `other`, karena bilangan tidak +# mengubah bentuk nomina. +example.files_processed = { $count -> + *[other] { $count } berkas diproses. +} + +example.errors_found = { $count -> + [0] Tidak ada galat yang ditemukan. + *[other] { $count } galat ditemukan. +} diff --git a/locales/it/messages.ftl b/locales/it/messages.ftl new file mode 100644 index 000000000..3c22a84f2 --- /dev/null +++ b/locales/it/messages.ftl @@ -0,0 +1,398 @@ +# Risorse di localizzazione per la CLI di Netsuke. + +cli.about = Netsuke compila manifest YAML + Jinja in piani di build Ninja. +cli.long_about = Netsuke trasforma manifest YAML + Jinja in grafi Ninja riproducibili ed esegue Ninja con impostazioni predefinite sicure. +cli.usage = { $usage } + +# Testo di aiuto delle opzioni globali. +cli.flag.file.help = Percorso del file manifest Netsuke da usare. +cli.flag.directory.help = Esegui come se fosse stato avviato in questa directory. +cli.flag.config.help = Percorso di un file di configurazione, ignorando la ricerca automatica. +cli.flag.jobs.help = Imposta il numero di job di build in parallelo. +cli.flag.verbose.help = Abilita log diagnostici dettagliati e riepiloghi dei tempi al termine. +cli.flag.locale.help = Tag di lingua per i testi della CLI (per esempio: en-US, it). +cli.flag.fetch_allow_scheme.help = Schemi URL aggiuntivi consentiti per l'helper fetch. +cli.flag.fetch_allow_host.help = Nomi host consentiti quando il diniego predefinito è attivo. +cli.flag.fetch_block_host.help = Nomi host sempre bloccati, anche se consentiti altrove. +cli.flag.fetch_default_deny.help = Nega tutti gli host per impostazione predefinita; consenti solo l'elenco dichiarato. +cli.flag.json.help = Produci output JSON leggibile da una macchina. +cli.flag.no_input.help = Non leggere mai input interattivo. +cli.flag.color.help = Criterio per l'output a colori (auto, always, never). +cli.flag.emoji.help = Criterio per le emoji (auto, always, never). +cli.flag.progress.help = Criterio di visualizzazione dell'avanzamento (auto, always, never). +cli.flag.accessibility.help = Criterio per l'output accessibile (auto, on, off). +cli.flag.default_targets.help = Target di build predefiniti quando non ne viene indicato alcuno. + +# Descrizioni dei sottocomandi. +cli.subcommand.build.about = Compila i target definiti nel manifest (predefinito). +cli.subcommand.build.long_about = Compila i target richiesti; se non ne vengono indicati, usa quelli predefiniti del manifest. +cli.subcommand.clean.about = Rimuovi gli artefatti di build tramite Ninja. +cli.subcommand.clean.long_about = Genera un file Ninja temporaneo, quindi esegui `ninja -t clean`. +cli.subcommand.graph.about = Emetti il grafo delle dipendenze di build. Il formato predefinito è DOT. +cli.subcommand.graph.long_about = Proietta il manifest Netsuke analizzato in un grafo di build canonico e scrivilo come Graphviz DOT, oppure come pagina HTML autonoma con `--html`. Usa `--output ` per scrivere su file; `-` scrive su stdout. +cli.subcommand.generate.about = Genera il manifest Ninja senza eseguire Ninja. +cli.subcommand.generate.long_about = Scrivi il manifest Ninja generato su stdout oppure nel file scelto con `--output`. + +# Testo di aiuto delle opzioni del sottocomando build. +cli.subcommand.build.flag.targets.help = Target da compilare (se omesso usa quelli predefiniti del manifest). + +# Testo di aiuto delle opzioni del sottocomando graph. +cli.subcommand.graph.flag.html.help = Genera il grafo come pagina HTML autonoma anziché come DOT. +cli.subcommand.graph.flag.output.help = Scrivi l'artefatto del grafo su FILE; usa `-` per stdout. + +# Testo di aiuto delle opzioni del sottocomando generate. +cli.subcommand.generate.flag.output.help = Scrivi il manifest Ninja generato su FILE anziché su stdout. + +# Errori di validazione della CLI. +cli.validation.jobs.invalid_number = { $value } non è un numero valido. +cli.validation.jobs.out_of_range = Il numero di job deve essere compreso tra { $min } e { $max }. +cli.validation.scheme.empty = Lo schema non deve essere vuoto. +cli.validation.scheme.invalid_start = Lo schema «{ $scheme }» deve iniziare con una lettera ASCII. +cli.validation.scheme.invalid = Schema non valido «{ $scheme }». +cli.validation.locale.empty = Il tag di lingua non deve essere vuoto. +cli.validation.locale.invalid = Tag di lingua non valido «{ $locale }». +cli.validation.color.invalid = Criterio di colore non valido «{ $value }». Opzioni valide: auto, always, never. +cli.validation.emoji.invalid = Criterio per le emoji non valido «{ $value }». Opzioni valide: auto, always, never. +cli.validation.progress.invalid = Criterio di avanzamento non valido «{ $value }». Opzioni valide: auto, always, never. +cli.validation.accessibility.invalid = Criterio di accessibilità non valido «{ $value }». Opzioni valide: auto, on, off. +cli.validation.config.expected_object = I valori della CLI dovevano essere serializzati in un oggetto, ricevuto { $value }. + +# Messaggi di errore di Clap. +clap-error-missing-argument = Argomento obbligatorio mancante: { $argument } +clap-error-missing-subcommand = Sottocomando mancante. Opzioni disponibili: { $valid_subcommands } +clap-error-unknown-argument = Argomento sconosciuto: { $argument } +clap-error-invalid-value = Valore non valido per { $argument }: { $value } +clap-error-invalid-subcommand = Sottocomando sconosciuto: { $subcommand } +# Nota: value-validation usa una formulazione diversa da invalid-value per +# distinguere gli errori dei validatori personalizzati +# (ErrorKind::ValueValidation) dalle incompatibilità di tipo +# (ErrorKind::InvalidValue). +clap-error-value-validation = Validazione non riuscita per { $argument }: { $value } + +# Errori e contesti del runner. +runner.manifest.not_found = Manifest «{ $manifest_name }» non trovato in { $directory }. +runner.manifest.not_found.help = Verifica che il manifest esista oppure indica `--file` con il percorso corretto. +runner.manifest.path_missing_name = Il percorso del manifest «{ $path }» non contiene un nome di file. +runner.manifest.path_utf8 = Il percorso del manifest «{ $path }» non è UTF-8 valido. +runner.manifest.directory_utf8 = Il percorso della directory del manifest «{ $path }» non è UTF-8 valido. +runner.manifest.directory_label = directory `{ $directory }` +runner.manifest.current_directory_label = la directory corrente +runner.context.network_policy = Impossibile costruire il criterio di rete. +runner.context.load_manifest = Impossibile caricare il manifest in { $path }. +runner.context.serialise_manifest = Impossibile serializzare il manifest. +runner.context.build_graph = Impossibile costruire il grafo a partire dal manifest. +runner.context.generate_ninja = Impossibile generare il manifest Ninja. +runner.context.render_graph = Impossibile generare l'artefatto del grafo. + +runner.io.create_temp_file = Impossibile creare il file Ninja temporaneo. +runner.io.write_temp_ninja = Impossibile scrivere il file Ninja temporaneo. +runner.io.flush_temp_ninja = Impossibile svuotare il buffer del file Ninja temporaneo. +runner.io.sync_temp_ninja = Impossibile sincronizzare il file Ninja temporaneo. +runner.io.create_parent_dir = Impossibile creare la directory padre { $path }. +runner.io.create_ninja_file = Impossibile creare il file Ninja in { $path }. +runner.io.write_ninja_file = Impossibile scrivere il file Ninja in { $path }. +runner.io.flush_ninja_file = Impossibile svuotare il buffer del file Ninja in { $path }. +runner.io.sync_ninja_file = Impossibile sincronizzare il file Ninja in { $path }. +runner.io.open_ambient_dir = Impossibile aprire la directory ambientale. +runner.io.no_existing_ancestor = Nessuna directory antenata esistente per { $path }. +runner.io.derive_relative_path = Impossibile derivare il percorso Ninja relativo. +runner.io.non_utf8_path = I percorsi non UTF-8 non sono supportati (percorso: { $path }). +runner.io.write_stdout = Impossibile scrivere il manifest Ninja su stdout. +runner.io.flush_stdout = Impossibile svuotare il buffer di stdout. + +# Diagnostica del manifest. +manifest.parse = Analisi del manifest non riuscita. +manifest.structure_error = Errore di struttura del manifest in { $name }: { $details } +manifest.yaml.parse = Errore di analisi YAML alla riga { $line }, colonna { $column }: { $details } +manifest.yaml.label = YAML non valido +manifest.yaml.hint.tabs = YAML non ammette tabulazioni; usa spazi per l'indentazione. +manifest.yaml.hint.list_item = Gli elementi di elenco YAML devono iniziare con «-» ed essere indentati correttamente. +manifest.yaml.hint.expected_colon = Sembra una voce di mappatura; manca il «:» dopo la chiave. +manifest.yaml.hint.mapping_values = Le mappature YAML richiedono un valore dopo «:» (oppure un blocco annidato). +manifest.yaml.hint.invalid_token = Il token YAML non è valido o è inatteso. +manifest.yaml.hint.escape = Usa l'escape per le barre rovesciate o rimuovi le sequenze di escape non valide. +manifest.env.missing = La variabile d'ambiente richiesta «{ $name }» non è impostata. +manifest.env.invalid_utf8 = La variabile d'ambiente «{ $name }» contiene UTF-8 non valido. +manifest.vars.not_object = `vars` del manifest deve essere una mappa o un oggetto. +manifest.read_failed = Impossibile leggere il manifest in { $path }. +manifest.resolve_workspace_root = Impossibile risolvere la radice dell'area di lavoro. +manifest.workspace_non_utf8 = Il percorso radice dell'area di lavoro «{ $path }» non è UTF-8 valido. +manifest.path_non_utf8 = Il percorso del manifest «{ $manifest }» non è UTF-8 valido: { $path }. +manifest.path_missing_name = Il percorso del manifest «{ $path }» non contiene un nome di file. +manifest.open_workspace_failed = Impossibile aprire l'area di lavoro { $workspace } per il manifest { $manifest }. +manifest.foreach.not_iterable = L'espressione `foreach` non è iterabile. +manifest.foreach.serialise_item = Impossibile serializzare l'elemento di `foreach`. +manifest.when.empty = L'espressione `when` non deve essere vuota. +manifest.when.eval_error = Impossibile valutare l'espressione `when` «{ $expr }». +manifest.when.template_error = Impossibile generare il template `when` «{ $expr }». +manifest.target.vars_not_object = `vars` del target deve essere un oggetto, ricevuto { $value }. +manifest.vars.entry_not_object = Una voce `vars` del manifest deve essere un oggetto. +manifest.field_not_string = Il campo «{ $field }» deve essere una stringa. +manifest.expression.parse_error = Impossibile analizzare l'espressione { $name }. +manifest.expression.eval_error = Impossibile valutare l'espressione { $name }. + +# Diagnostica delle macro del manifest. +manifest.macro.signature_missing_identifier = Alla firma della macro manca un identificatore. +manifest.macro.signature_missing_params = Alla firma della macro mancano i parametri. +manifest.macro.compile_failed = Impossibile compilare la macro { $name }. +manifest.macro.sequence_invalid = Le macro devono essere definite come mappatura da nomi a template. +manifest.macro.register_failed = Impossibile registrare le macro del manifest. +manifest.macro.not_initialised = L'ambiente delle macro non è inizializzato. +manifest.macro.caller_invalid = Il chiamante della macro deve essere una stringa. +manifest.macro.template_load_failed = Impossibile caricare il template della macro. +manifest.macro.init_failed = Impossibile inizializzare l'ambiente delle macro. +manifest.macro.missing = La macro { $name } è mancante. + +# Errori dei pattern glob del manifest. +manifest.glob.unmatched_brace = Pattern glob non valido «{ $pattern }»: «{ $character }» senza corrispondenza alla posizione { $position }. +manifest.glob.invalid_pattern = Pattern glob non valido «{ $pattern }»: { $detail }. +manifest.glob.unknown_pattern_error = errore di pattern sconosciuto. +manifest.glob.io_failed = Glob non riuscito per «{ $pattern }»: { $detail }. +manifest.glob.unknown_io_error = errore di I/O sconosciuto. + +# Errori della rappresentazione intermedia. +ir.rule_not_found = La regola «{ $rule }» referenziata dal target «{ $target }» non è stata trovata. +ir.multiple_rules = Il target «{ $target }» deve referenziare una sola regola, ricevuto { $rules }. +ir.empty_rule = Il target «{ $target }» deve referenziare una regola. +ir.duplicate_outputs = Rilevati output duplicati: { $outputs }. +ir.circular_dependency = Rilevata dipendenza circolare: { $cycle }. +ir.action_serialisation = Impossibile serializzare l'azione: { $details }. +ir.invalid_command = Interpolazione del comando non valida: { $snippet }. + +# Errori di generazione Ninja. +ninja_gen.missing_action = Manca l'azione «{ $id }» referenziata da un arco di build. +ninja_gen.format = Impossibile formattare l'output del manifest Ninja. + +# Validazione dei pattern host. +host_pattern.empty = Il pattern host non deve essere vuoto. +host_pattern.contains_scheme = Il pattern host «{ $pattern }» non deve includere uno schema URL. +host_pattern.contains_slash = Il pattern host «{ $pattern }» non deve contenere «/». +host_pattern.missing_suffix = Il pattern host «{ $pattern }» deve includere un suffisso dopo «*.». +host_pattern.empty_label = Il pattern host «{ $pattern }» contiene un'etichetta vuota. +host_pattern.invalid_chars = Il pattern host «{ $pattern }» contiene caratteri non validi. +host_pattern.invalid_label_edge = Le etichette del pattern host «{ $pattern }» non devono iniziare o terminare con «-». +host_pattern.label_too_long = Il pattern host «{ $pattern }» contiene un'etichetta più lunga di 63 caratteri. +host_pattern.too_long = Il pattern host «{ $pattern }» supera il limite di 255 caratteri. + +# Criteri di rete. +network_policy.scheme.empty = Lo schema non deve essere vuoto. +network_policy.scheme.invalid = Lo schema «{ $scheme }» contiene caratteri non validi. +network_policy.allowlist.empty = L'elenco degli host consentiti non deve essere vuoto. +network_policy.scheme.not_allowed = Lo schema «{ $scheme }» non è consentito. +network_policy.missing_host = L'URL non contiene un host. +network_policy.host.blocked = L'host «{ $host }» è bloccato dal criterio. +network_policy.host.not_allowlisted = L'host «{ $host }» non è nell'elenco dei consentiti. + +# Configurazione della libreria standard. +stdlib.config.default_fetch_cache_invalid = Il percorso predefinito della cache di fetch deve essere relativo. +stdlib.config.default_which_cache_invalid = La capacità predefinita della cache di which deve essere positiva. +stdlib.config.workspace_root_absolute = Il percorso radice dell'area di lavoro deve essere assoluto. +stdlib.config.fetch_response_limit_positive = Il limite di risposta di fetch deve essere positivo. +stdlib.config.command_output_limit_positive = Il limite di cattura dell'output dei comandi deve essere positivo. +stdlib.config.command_stream_limit_positive = Il limite di streaming dei comandi deve essere positivo. +stdlib.config.which_cache_capacity_positive = La capacità della cache di which deve essere positiva. +stdlib.config.skip_dir_empty = Le voci di directory da ignorare non devono essere vuote. +stdlib.config.skip_dir_navigation = Le voci di directory da ignorare non devono contenere «..». +stdlib.config.skip_dir_separator = Le voci di directory da ignorare non devono contenere separatori di percorso. +stdlib.config.fetch_cache_empty = Il percorso della cache di fetch non deve essere vuoto. +stdlib.config.fetch_cache_not_relative = Il percorso della cache di fetch deve essere relativo, ricevuto { $path }. +stdlib.config.fetch_cache_escapes = Il percorso della cache di fetch non deve uscire dall'area di lavoro: { $path }. +stdlib.config.open_workspace_root = Impossibile aprire la directory corrente come radice dell'area di lavoro della stdlib. +stdlib.config.resolve_cwd = Impossibile risolvere la directory corrente come radice dell'area di lavoro della stdlib. +stdlib.config.cwd_non_utf8 = La directory corrente contiene componenti non UTF-8: { $path }. + +# Diagnostica dell'helper fetch. +stdlib.fetch.url_invalid = URL non valido «{ $url }»: { $details }. +stdlib.fetch.disallowed = L'URL «{ $url }» non è consentito: { $details }. +stdlib.fetch.failed = Impossibile scaricare «{ $url }»: { $details }. +stdlib.fetch.cache_read_failed = Impossibile leggere la voce di cache «{ $name }»: { $details }. +stdlib.fetch.cache_open_failed = Impossibile aprire la voce di cache «{ $name }»: { $details }. +stdlib.fetch.response_read_failed = Impossibile leggere la risposta da «{ $url }»: { $details }. +stdlib.fetch.response_buffer_overflow = Overflow del buffer durante la lettura di «{ $url }». +stdlib.fetch.cache_write_failed = Impossibile scrivere la cache per «{ $url }»: { $details }. +stdlib.fetch.response_limit_exceeded = La risposta da «{ $url }» ha superato il limite di { $limit } byte. +stdlib.fetch.cache_limit_exceeded = La risposta in cache «{ $name }» ha superato il limite di { $limit } byte. +stdlib.fetch.io_failed = L'operazione di { $action } non è riuscita per { $path }: { $details }. +stdlib.fetch.action.sync_cache = sincronizzare la cache di fetch +stdlib.fetch.action.create_cache_dir = creare la directory di cache di fetch +stdlib.fetch.action.open_cache_dir = aprire la directory di cache di fetch +stdlib.fetch.action.stat_cache = interrogare la voce di cache di fetch +stdlib.fetch.action.open_cache_entry = aprire la voce di cache di fetch + +# Diagnostica dell'helper dei comandi. +stdlib.command.location = comando «{ $command }» nel template «{ $template }» +stdlib.command.spawn_failed = Impossibile avviare { $location }: { $details }. +stdlib.command.io_failed = { $location } non riuscito: { $details }. +stdlib.command.closed_input_early = L'input si è chiuso prima di completare la scrittura verso il comando. +stdlib.command.broken_pipe = Pipe interrotta durante l'esecuzione di { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } è stato terminato da un segnale. +stdlib.command.exited_with_status = { $location } è terminato con stato { $status }. +stdlib.command.output_limit_exceeded = { $location } ha superato il limite { $mode } di { $limit } byte per { $stream }. +stdlib.command.timeout = { $location } ha superato il tempo limite di { $seconds } secondi. +stdlib.command.exit_status_suffix = (stato di uscita { $status }) +stdlib.command.signal_suffix = (terminato da un segnale) +stdlib.command.shell.empty = Il comando shell non deve essere vuoto. +stdlib.command.grep.empty_pattern = Il pattern di grep non deve essere vuoto. +stdlib.command.grep.flags_not_string = Le opzioni di grep devono essere stringhe. +stdlib.command.quote.invalid = Impossibile applicare le virgolette a { $arg }: { $details }. +stdlib.command.quote.line_break = Gli argomenti con ritorni a capo o avanzamenti di riga non possono essere racchiusi tra virgolette in sicurezza. +stdlib.command.input_undefined = Il valore di input non è definito. +stdlib.command.tempfile.root_required = Per creare file temporanei dei comandi è necessaria la radice dell'area di lavoro. +stdlib.command.tempfile.create_failed = Impossibile creare il file temporaneo del comando: { $details }. +stdlib.command.options.invalid_utf8 = La chiave di un'opzione del comando deve essere UTF-8 valido. +stdlib.command.option.mode_not_string = La modalità di output deve essere una stringa. +stdlib.command.options.invalid_type = Le opzioni del comando devono essere un oggetto. +stdlib.command.output.mode_unsupported = Modalità di output non supportata «{ $mode }». +stdlib.command.output.mode.capture = cattura +stdlib.command.output.mode.streaming = streaming +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Diagnostica dell'helper dei percorsi. +stdlib.path.io.failed = L'operazione di { $action } non è riuscita per { $path } ({ $label }). +stdlib.path.io.failed_with_detail = L'operazione di { $action } non è riuscita per { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = L'operazione di { $action } non è riuscita per { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = non trovato +stdlib.path.io.permission_denied = autorizzazione negata +stdlib.path.io.already_exists = già esistente +stdlib.path.io.invalid_input = input non valido +stdlib.path.io.invalid_data = dati non validi +stdlib.path.io.timed_out = tempo scaduto +stdlib.path.io.interrupted = interrotto +stdlib.path.io.would_block = si bloccherebbe +stdlib.path.io.write_zero = scrittura nulla +stdlib.path.io.unexpected_eof = fine del file inattesa +stdlib.path.io.broken_pipe = pipe interrotta +stdlib.path.io.connection_refused = connessione rifiutata +stdlib.path.io.connection_reset = connessione reimpostata +stdlib.path.io.connection_aborted = connessione interrotta +stdlib.path.io.not_connected = non connesso +stdlib.path.io.addr_in_use = indirizzo già in uso +stdlib.path.io.addr_not_available = indirizzo non disponibile +stdlib.path.io.out_of_memory = memoria esaurita +stdlib.path.io.unsupported = non supportato +stdlib.path.io.file_too_large = file troppo grande +stdlib.path.io.resource_busy = risorsa occupata +stdlib.path.io.executable_busy = eseguibile occupato +stdlib.path.io.deadlock = stallo +stdlib.path.io.crosses_devices = attraversa dispositivi diversi +stdlib.path.io.too_many_links = troppi collegamenti +stdlib.path.io.invalid_filename = nome di file non valido +stdlib.path.io.arg_list_too_long = elenco di argomenti troppo lungo +stdlib.path.io.stale_handle = handle di file di rete obsoleto +stdlib.path.io.storage_full = spazio di archiviazione esaurito +stdlib.path.io.not_seekable = posizionamento non consentito +stdlib.path.io.network_down = rete non attiva +stdlib.path.io.network_unreachable = rete irraggiungibile +stdlib.path.io.host_unreachable = host irraggiungibile +stdlib.path.io.other = errore di I/O +stdlib.path.action.canonicalize = canonicalizzare +stdlib.path.action.open_directory = aprire la directory +stdlib.path.action.stat = interrogare +stdlib.path.action.read = leggere +stdlib.path.action.open_file = aprire il file +stdlib.path.with_suffix.empty_separator = with_suffix richiede un separatore non vuoto. +stdlib.path.relative_to.mismatch = { $path } non è relativo a { $root }. +stdlib.path.expanduser.unsupported = L'espansione di ~ per uno specifico utente non è supportata. +stdlib.path.expanduser.no_home = Impossibile espandere ~: non è impostata alcuna variabile d'ambiente per la directory home. +stdlib.path.contents.unsupported_encoding = Codifica non supportata «{ $encoding }». +stdlib.path.hash.unsupported_algorithm = Algoritmo di hash non supportato «{ $algorithm }». +stdlib.path.hash.unsupported_algorithm_legacy = Algoritmo di hash non supportato «{ $algorithm }» (abilita la funzionalità «{ $feature }»). + +# Diagnostica degli helper per le collezioni. +stdlib.collections.flatten.expected_sequence = flatten si aspettava elementi di sequenza ma ha trovato { $kind }. +stdlib.collections.group_by.empty_attribute = group_by richiede un attributo non vuoto. +stdlib.collections.group_by.unresolved = group_by non ha potuto risolvere «{ $attr }» su un elemento di tipo { $kind }. + +# Diagnostica degli helper temporali. +stdlib.time.offset.invalid = L'offset di now «{ $offset }» non è valido: previsto «+HH:MM[:SS]» oppure «Z». +stdlib.time.timedelta.overflow = Overflow di timedelta durante l'aggiunta di { $component }. +stdlib.time.label.weeks = settimane +stdlib.time.label.days = giorni +stdlib.time.label.hours = ore +stdlib.time.label.minutes = minuti +stdlib.time.label.seconds = secondi +stdlib.time.label.milliseconds = millisecondi +stdlib.time.label.microseconds = microsecondi +stdlib.time.label.nanoseconds = nanosecondi + +# Diagnostica dell'helper which. +stdlib.which.not_found = [netsuke::jinja::which::not_found] comando «{ $command }» non trovato dopo aver controllato { $count } voci di PATH. Anteprima: { $preview } +stdlib.which.not_found.hint.cwd_auto = I segmenti vuoti di PATH vengono ignorati; usa cwd_mode="auto" per includere la directory di lavoro. +stdlib.which.not_found.hint.cwd_always = Imposta cwd_mode="always" per includere la directory corrente. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] il comando «{ $command }» in «{ $path }» è assente o non eseguibile. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = La voce PATH n. { $index } contiene caratteri non UTF-8; Netsuke richiede percorsi UTF-8. +stdlib.which.command.empty = which richiede una stringa non vuota. +stdlib.which.cwd_mode.invalid = cwd_mode deve essere «auto», «always» o «never», ricevuto «{ $mode }». +stdlib.which.cwd.resolve_failed = Impossibile risolvere la directory corrente: { $details }. +stdlib.which.cwd.non_utf8 = La directory corrente contiene componenti non UTF-8. +stdlib.which.canonicalize_failed = Impossibile canonicalizzare «{ $path }»: { $details }. +stdlib.which.is_executable = Impossibile verificare se «{ $path }» è eseguibile: { $details }. +stdlib.which.canonicalize_non_utf8 = Il percorso canonico contiene componenti non UTF-8. +stdlib.which.workspace_non_utf8 = Il percorso dell'area di lavoro contiene componenti non UTF-8 durante la risoluzione del comando «{ $command }»: { $path }. +stdlib.which.walkdir_error = Errore nell'attraversamento dell'area di lavoro durante la risoluzione del comando: { $details }. + +# Registrazione della libreria standard. +stdlib.register.open_dir = Impossibile aprire la directory corrente per la registrazione della stdlib. +stdlib.register.resolve_dir = Impossibile risolvere la directory corrente per la registrazione della stdlib. +stdlib.register.dir_non_utf8 = La directory corrente contiene componenti non UTF-8: { $path }. + +# Segnalazione di stato per la modalità di output accessibile. +status.state.pending = in attesa +status.state.running = in corso +status.state.done = completata +status.state.failed = non riuscita +status.stage.label = Fase { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Attività { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Lettura del file manifest +status.stage.initial_yaml_parsing = Analisi del documento YAML +status.stage.template_expansion = Espansione delle direttive dei template +status.stage.final_rendering = Deserializzazione e rendering dei valori del manifest +status.stage.ir_generation_validation = Costruzione e validazione del grafo delle dipendenze +status.stage.ninja_synthesis = Sintesi del piano di build Ninja +status.stage.ninja_synthesis_execute = Sintesi del piano Ninja ed esecuzione di { $tool } +status.stage.graph_rendering = Rendering dell'artefatto del grafo +status.stage.graph_rendering_with_tool = Rendering di { $tool } +status.complete = { $tool }: operazione completata. +status.timing.summary_header = Riepilogo dei tempi per fase: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Tempo totale della pipeline: { $duration } +status.tool.build = Build +status.tool.clean = Pulizia +status.tool.graph = Grafo +status.tool.graph_html = Grafo (HTML) +status.tool.generate = Generazione + +# Stringhe del renderer HTML del grafo. +graph.html.title = Grafo di build di Netsuke +graph.html.heading = Grafo di build di Netsuke +graph.html.description = Grafo di build generato da Netsuke +graph.html.outline.summary = Target e dipendenze (schema testuale) +graph.html.outline.no_inputs = Nessun input +graph.html.noscript.notice = JavaScript è disattivato. Lo schema testuale qui sopra contiene il grafo completo; segue il sorgente DOT. + +# Prefissi semantici per l'output accessibile. +semantic.prefix.error = Errore: +semantic.prefix.warning = Avviso: +semantic.prefix.success = Operazione riuscita: +semantic.prefix.info = Info: +semantic.prefix.timing = Tempi: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Esempi di forme plurali per i traduttori. +# L'italiano usa le categorie CLDR `one` e `other`, come la lingua di origine. +example.files_processed = { $count -> + [one] Elaborato { $count } file. + *[other] Elaborati { $count } file. +} + +example.errors_found = { $count -> + [0] Nessun errore trovato. + [one] Trovato { $count } errore. + *[other] Trovati { $count } errori. +} diff --git a/locales/ja/messages.ftl b/locales/ja/messages.ftl new file mode 100644 index 000000000..175475207 --- /dev/null +++ b/locales/ja/messages.ftl @@ -0,0 +1,395 @@ +# Netsuke コマンドラインのローカライズリソース。 + +cli.about = Netsuke は YAML + Jinja のマニフェストを Ninja のビルド計画にコンパイルします。 +cli.long_about = Netsuke は YAML + Jinja のマニフェストを再現可能な Ninja グラフに変換し、安全な既定値で Ninja を実行します。 +cli.usage = { $usage } + +# 全体オプションのヘルプ文。 +cli.flag.file.help = 使用する Netsuke マニフェストファイルのパス。 +cli.flag.directory.help = このディレクトリーで起動したものとして実行します。 +cli.flag.config.help = 自動検出を行わずに使用する設定ファイルのパス。 +cli.flag.jobs.help = 並列に実行するビルドジョブ数を指定します。 +cli.flag.verbose.help = 詳細な診断ログと完了時の所要時間サマリーを有効にします。 +cli.flag.locale.help = コマンドライン文言のロケールタグ(例: en-US、ja)。 +cli.flag.fetch_allow_scheme.help = fetch ヘルパーで追加的に許可する URL スキーム。 +cli.flag.fetch_allow_host.help = 既定の拒否が有効なときに許可するホスト名。 +cli.flag.fetch_block_host.help = 他で許可されていても常に遮断するホスト名。 +cli.flag.fetch_default_deny.help = 既定ですべてのホストを拒否し、宣言した許可リストのみを通します。 +cli.flag.json.help = 機械可読な JSON を出力します。 +cli.flag.no_input.help = 対話的な入力を一切読み取りません。 +cli.flag.color.help = 色付き出力の方針(auto、always、never)。 +cli.flag.emoji.help = 絵文字の方針(auto、always、never)。 +cli.flag.progress.help = 進捗表示の方針(auto、always、never)。 +cli.flag.accessibility.help = アクセシブル出力の方針(auto、on、off)。 +cli.flag.default_targets.help = ターゲットが指定されない場合の既定のビルドターゲット。 + +# サブコマンドの説明。 +cli.subcommand.build.about = マニフェストで定義したターゲットをビルドします(既定)。 +cli.subcommand.build.long_about = 要求されたターゲットをビルドします。指定がない場合はマニフェストの既定ターゲットを使います。 +cli.subcommand.clean.about = Ninja を介してビルド成果物を削除します。 +cli.subcommand.clean.long_about = 一時的な Ninja ファイルを生成し、続いて `ninja -t clean` を実行します。 +cli.subcommand.graph.about = ビルドの依存グラフを出力します。既定の形式は DOT です。 +cli.subcommand.graph.long_about = 解析済みの Netsuke マニフェストを正準形のビルドグラフに射影し、Graphviz DOT として、または `--html` を指定した場合は自己完結型の HTML ページとして書き出します。ファイルへ書き出すには `--output <ファイル>` を使い、`-` を指定すると標準出力に書き出します。 +cli.subcommand.generate.about = Ninja を実行せずに Ninja マニフェストを生成します。 +cli.subcommand.generate.long_about = 生成した Ninja マニフェストを標準出力、または `--output` で選んだファイルに書き出します。 + +# build サブコマンドのオプションのヘルプ文。 +cli.subcommand.build.flag.targets.help = ビルドするターゲット(省略時はマニフェストの既定値を使用)。 + +# graph サブコマンドのオプションのヘルプ文。 +cli.subcommand.graph.flag.html.help = グラフを DOT ではなく自己完結型の HTML ページとして描画します。 +cli.subcommand.graph.flag.output.help = グラフ成果物をファイルに書き出します。標準出力には `-` を使います。 + +# generate サブコマンドのオプションのヘルプ文。 +cli.subcommand.generate.flag.output.help = 生成した Ninja マニフェストを標準出力ではなくファイルに書き出します。 + +# コマンドラインの検証エラー。 +cli.validation.jobs.invalid_number = { $value } は有効な数値ではありません。 +cli.validation.jobs.out_of_range = ジョブ数は { $min } から { $max } の範囲でなければなりません。 +cli.validation.scheme.empty = スキームを空にすることはできません。 +cli.validation.scheme.invalid_start = スキーム「{ $scheme }」は ASCII 文字で始まる必要があります。 +cli.validation.scheme.invalid = 無効なスキーム「{ $scheme }」です。 +cli.validation.locale.empty = ロケールタグを空にすることはできません。 +cli.validation.locale.invalid = 無効なロケールタグ「{ $locale }」です。 +cli.validation.color.invalid = 無効な色の方針「{ $value }」です。有効な選択肢: auto、always、never。 +cli.validation.emoji.invalid = 無効な絵文字の方針「{ $value }」です。有効な選択肢: auto、always、never。 +cli.validation.progress.invalid = 無効な進捗の方針「{ $value }」です。有効な選択肢: auto、always、never。 +cli.validation.accessibility.invalid = 無効なアクセシビリティの方針「{ $value }」です。有効な選択肢: auto、on、off。 +cli.validation.config.expected_object = コマンドラインの値はオブジェクトへ直列化されるはずでしたが、{ $value } が得られました。 + +# Clap のエラーメッセージ。 +clap-error-missing-argument = 必須の引数がありません: { $argument } +clap-error-missing-subcommand = サブコマンドがありません。利用できる選択肢: { $valid_subcommands } +clap-error-unknown-argument = 不明な引数です: { $argument } +clap-error-invalid-value = { $argument } の値が無効です: { $value } +clap-error-invalid-subcommand = 不明なサブコマンドです: { $subcommand } +# 注記: value-validation は invalid-value とは異なる表現にして、独自バリデーター +# の失敗(ErrorKind::ValueValidation)と型の不一致(ErrorKind::InvalidValue)を +# 区別しています。 +clap-error-value-validation = { $argument } の検証に失敗しました: { $value } + +# 実行時のエラーと文脈。 +runner.manifest.not_found = マニフェスト「{ $manifest_name }」が { $directory } に見つかりません。 +runner.manifest.not_found.help = マニフェストが存在することを確認するか、正しいパスを指定して `--file` を渡してください。 +runner.manifest.path_missing_name = マニフェストのパス「{ $path }」にファイル名がありません。 +runner.manifest.path_utf8 = マニフェストのパス「{ $path }」は有効な UTF-8 ではありません。 +runner.manifest.directory_utf8 = マニフェストのディレクトリーパス「{ $path }」は有効な UTF-8 ではありません。 +runner.manifest.directory_label = ディレクトリー `{ $directory }` +runner.manifest.current_directory_label = 現在のディレクトリー +runner.context.network_policy = ネットワークポリシーを構築できませんでした。 +runner.context.load_manifest = { $path } のマニフェストを読み込めませんでした。 +runner.context.serialise_manifest = マニフェストを直列化できませんでした。 +runner.context.build_graph = マニフェストからグラフを構築できませんでした。 +runner.context.generate_ninja = Ninja マニフェストを生成できませんでした。 +runner.context.render_graph = グラフ成果物を描画できませんでした。 + +runner.io.create_temp_file = 一時 Ninja ファイルを作成できませんでした。 +runner.io.write_temp_ninja = 一時 Ninja ファイルに書き込めませんでした。 +runner.io.flush_temp_ninja = 一時 Ninja ファイルのバッファーを書き出せませんでした。 +runner.io.sync_temp_ninja = 一時 Ninja ファイルを同期できませんでした。 +runner.io.create_parent_dir = 親ディレクトリー { $path } を作成できませんでした。 +runner.io.create_ninja_file = { $path } に Ninja ファイルを作成できませんでした。 +runner.io.write_ninja_file = { $path } の Ninja ファイルに書き込めませんでした。 +runner.io.flush_ninja_file = { $path } の Ninja ファイルのバッファーを書き出せませんでした。 +runner.io.sync_ninja_file = { $path } の Ninja ファイルを同期できませんでした。 +runner.io.open_ambient_dir = 周囲のディレクトリーを開けませんでした。 +runner.io.no_existing_ancestor = { $path } に対応する既存の上位ディレクトリーがありません。 +runner.io.derive_relative_path = Ninja の相対パスを導出できませんでした。 +runner.io.non_utf8_path = UTF-8 でないパスには対応していません(パス: { $path })。 +runner.io.write_stdout = Ninja マニフェストを標準出力に書き込めませんでした。 +runner.io.flush_stdout = 標準出力のバッファーを書き出せませんでした。 + +# マニフェストの診断。 +manifest.parse = マニフェストの解析に失敗しました。 +manifest.structure_error = { $name } でマニフェストの構造エラー: { $details } +manifest.yaml.parse = { $line } 行 { $column } 桁で YAML の解析エラー: { $details } +manifest.yaml.label = 無効な YAML +manifest.yaml.hint.tabs = YAML はタブを許しません。字下げには空白を使ってください。 +manifest.yaml.hint.list_item = YAML のリスト項目は「-」で始め、正しく字下げする必要があります。 +manifest.yaml.hint.expected_colon = マッピングの項目のようです。キーの後に「:」がありません。 +manifest.yaml.hint.mapping_values = YAML のマッピングは「:」の後に値(または入れ子のブロック)が必要です。 +manifest.yaml.hint.invalid_token = YAML のトークンが無効か、予期しないものです。 +manifest.yaml.hint.escape = 逆斜線をエスケープするか、無効なエスケープ列を取り除いてください。 +manifest.env.missing = 必須の環境変数「{ $name }」が設定されていません。 +manifest.env.invalid_utf8 = 環境変数「{ $name }」に無効な UTF-8 が含まれています。 +manifest.vars.not_object = マニフェストの `vars` はマップまたはオブジェクトでなければなりません。 +manifest.read_failed = { $path } のマニフェストを読み取れませんでした。 +manifest.resolve_workspace_root = ワークスペースのルートを特定できませんでした。 +manifest.workspace_non_utf8 = ワークスペースのルートパス「{ $path }」は有効な UTF-8 ではありません。 +manifest.path_non_utf8 = マニフェスト「{ $manifest }」のパスは有効な UTF-8 ではありません: { $path }。 +manifest.path_missing_name = マニフェストのパス「{ $path }」にファイル名がありません。 +manifest.open_workspace_failed = マニフェスト { $manifest } のためにワークスペース { $workspace } を開けませんでした。 +manifest.foreach.not_iterable = `foreach` の式は反復できません。 +manifest.foreach.serialise_item = `foreach` の要素を直列化できませんでした。 +manifest.when.empty = `when` の式を空にすることはできません。 +manifest.when.eval_error = `when` の式「{ $expr }」を評価できませんでした。 +manifest.when.template_error = `when` のテンプレート「{ $expr }」を描画できませんでした。 +manifest.target.vars_not_object = ターゲットの `vars` はオブジェクトでなければなりませんが、{ $value } が得られました。 +manifest.vars.entry_not_object = マニフェストの `vars` の項目はオブジェクトでなければなりません。 +manifest.field_not_string = フィールド「{ $field }」は文字列でなければなりません。 +manifest.expression.parse_error = { $name } の式を解析できませんでした。 +manifest.expression.eval_error = { $name } の式を評価できませんでした。 + +# マニフェストのマクロの診断。 +manifest.macro.signature_missing_identifier = マクロのシグネチャーに識別子がありません。 +manifest.macro.signature_missing_params = マクロのシグネチャーに引数がありません。 +manifest.macro.compile_failed = マクロ { $name } をコンパイルできませんでした。 +manifest.macro.sequence_invalid = マクロは名前からテンプレートへのマッピングとして定義する必要があります。 +manifest.macro.register_failed = マニフェストのマクロを登録できませんでした。 +manifest.macro.not_initialised = マクロ環境が初期化されていません。 +manifest.macro.caller_invalid = マクロの呼び出し元は文字列でなければなりません。 +manifest.macro.template_load_failed = マクロのテンプレートを読み込めませんでした。 +manifest.macro.init_failed = マクロ環境を初期化できませんでした。 +manifest.macro.missing = マクロ { $name } がありません。 + +# マニフェストの glob エラー。 +manifest.glob.unmatched_brace = 無効な glob パターン「{ $pattern }」: 位置 { $position } の「{ $character }」に対応するものがありません。 +manifest.glob.invalid_pattern = 無効な glob パターン「{ $pattern }」: { $detail }。 +manifest.glob.unknown_pattern_error = 不明なパターンエラー。 +manifest.glob.io_failed = 「{ $pattern }」の glob に失敗しました: { $detail }。 +manifest.glob.unknown_io_error = 不明な入出力エラー。 + +# 中間表現のエラー。 +ir.rule_not_found = ターゲット「{ $target }」が参照する規則「{ $rule }」が見つかりません。 +ir.multiple_rules = ターゲット「{ $target }」は規則をちょうど 1 つ参照しなければなりませんが、{ $rules } が得られました。 +ir.empty_rule = ターゲット「{ $target }」は規則を参照しなければなりません。 +ir.duplicate_outputs = 出力の重複を検出しました: { $outputs }。 +ir.circular_dependency = 循環依存を検出しました: { $cycle }。 +ir.action_serialisation = アクションを直列化できませんでした: { $details }。 +ir.invalid_command = コマンドの補間が無効です: { $snippet }。 + +# Ninja 生成のエラー。 +ninja_gen.missing_action = ビルド辺が参照するアクション「{ $id }」がありません。 +ninja_gen.format = Ninja マニフェストの出力を整形できませんでした。 + +# ホストパターンの検証。 +host_pattern.empty = ホストパターンを空にすることはできません。 +host_pattern.contains_scheme = ホストパターン「{ $pattern }」に URL スキームを含めることはできません。 +host_pattern.contains_slash = ホストパターン「{ $pattern }」に「/」を含めることはできません。 +host_pattern.missing_suffix = ホストパターン「{ $pattern }」には「*.」の後に接尾辞が必要です。 +host_pattern.empty_label = ホストパターン「{ $pattern }」に空のラベルが含まれています。 +host_pattern.invalid_chars = ホストパターン「{ $pattern }」に無効な文字が含まれています。 +host_pattern.invalid_label_edge = ホストパターン「{ $pattern }」のラベルを「-」で始めたり終えたりすることはできません。 +host_pattern.label_too_long = ホストパターン「{ $pattern }」に 63 文字を超えるラベルが含まれています。 +host_pattern.too_long = ホストパターン「{ $pattern }」が 255 文字の上限を超えています。 + +# ネットワークポリシー。 +network_policy.scheme.empty = スキームを空にすることはできません。 +network_policy.scheme.invalid = スキーム「{ $scheme }」に無効な文字が含まれています。 +network_policy.allowlist.empty = ホストの許可リストを空にすることはできません。 +network_policy.scheme.not_allowed = スキーム「{ $scheme }」は許可されていません。 +network_policy.missing_host = URL にホストがありません。 +network_policy.host.blocked = ホスト「{ $host }」はポリシーにより遮断されています。 +network_policy.host.not_allowlisted = ホスト「{ $host }」は許可リストにありません。 + +# 標準ライブラリーの設定。 +stdlib.config.default_fetch_cache_invalid = fetch キャッシュの既定のパスは相対パスでなければなりません。 +stdlib.config.default_which_cache_invalid = which キャッシュの既定の容量は正の値でなければなりません。 +stdlib.config.workspace_root_absolute = ワークスペースのルートパスは絶対パスでなければなりません。 +stdlib.config.fetch_response_limit_positive = fetch の応答上限は正の値でなければなりません。 +stdlib.config.command_output_limit_positive = コマンド出力の取り込み上限は正の値でなければなりません。 +stdlib.config.command_stream_limit_positive = コマンドのストリーム上限は正の値でなければなりません。 +stdlib.config.which_cache_capacity_positive = which キャッシュの容量は正の値でなければなりません。 +stdlib.config.skip_dir_empty = 読み飛ばすディレクトリーの項目を空にすることはできません。 +stdlib.config.skip_dir_navigation = 読み飛ばすディレクトリーの項目に「..」を含めることはできません。 +stdlib.config.skip_dir_separator = 読み飛ばすディレクトリーの項目にパス区切り文字を含めることはできません。 +stdlib.config.fetch_cache_empty = fetch キャッシュのパスを空にすることはできません。 +stdlib.config.fetch_cache_not_relative = fetch キャッシュのパスは相対パスでなければなりませんが、{ $path } が得られました。 +stdlib.config.fetch_cache_escapes = fetch キャッシュのパスがワークスペースの外に出ることはできません: { $path }。 +stdlib.config.open_workspace_root = 現在のディレクトリーを stdlib のワークスペースルートとして開けませんでした。 +stdlib.config.resolve_cwd = 現在のディレクトリーを stdlib のワークスペースルートとして特定できませんでした。 +stdlib.config.cwd_non_utf8 = 現在のディレクトリーに UTF-8 でない部分が含まれています: { $path }。 + +# fetch ヘルパーの診断。 +stdlib.fetch.url_invalid = 無効な URL「{ $url }」: { $details }。 +stdlib.fetch.disallowed = URL「{ $url }」は許可されていません: { $details }。 +stdlib.fetch.failed = 「{ $url }」を取得できませんでした: { $details }。 +stdlib.fetch.cache_read_failed = キャッシュ項目「{ $name }」を読み取れませんでした: { $details }。 +stdlib.fetch.cache_open_failed = キャッシュ項目「{ $name }」を開けませんでした: { $details }。 +stdlib.fetch.response_read_failed = 「{ $url }」からの応答を読み取れませんでした: { $details }。 +stdlib.fetch.response_buffer_overflow = 「{ $url }」の読み取り中にバッファーがあふれました。 +stdlib.fetch.cache_write_failed = 「{ $url }」のキャッシュを書き込めませんでした: { $details }。 +stdlib.fetch.response_limit_exceeded = 「{ $url }」からの応答が { $limit } バイトの上限を超えました。 +stdlib.fetch.cache_limit_exceeded = キャッシュ済みの応答「{ $name }」が { $limit } バイトの上限を超えました。 +stdlib.fetch.io_failed = { $path } に対する「{ $action }」に失敗しました: { $details }。 +stdlib.fetch.action.sync_cache = fetch キャッシュの同期 +stdlib.fetch.action.create_cache_dir = fetch キャッシュディレクトリーの作成 +stdlib.fetch.action.open_cache_dir = fetch キャッシュディレクトリーを開く操作 +stdlib.fetch.action.stat_cache = fetch キャッシュ項目の情報取得 +stdlib.fetch.action.open_cache_entry = fetch キャッシュ項目を開く操作 + +# コマンドヘルパーの診断。 +stdlib.command.location = テンプレート「{ $template }」内のコマンド「{ $command }」 +stdlib.command.spawn_failed = { $location } を起動できませんでした: { $details }。 +stdlib.command.io_failed = { $location } が失敗しました: { $details }。 +stdlib.command.closed_input_early = コマンドへの書き込みが終わる前に入力が閉じられました。 +stdlib.command.broken_pipe = { $location } の実行中にパイプが切断されました: { $details }。 +stdlib.command.terminated_by_signal = { $location } はシグナルにより終了しました。 +stdlib.command.exited_with_status = { $location } は状態 { $status } で終了しました。 +stdlib.command.output_limit_exceeded = { $location } は { $stream } について { $mode } の上限 { $limit } バイトを超えました。 +stdlib.command.timeout = { $location } は { $seconds } 秒の制限時間を超えました。 +stdlib.command.exit_status_suffix = (終了状態 { $status }) +stdlib.command.signal_suffix = (シグナルにより終了) +stdlib.command.shell.empty = シェルコマンドを空にすることはできません。 +stdlib.command.grep.empty_pattern = grep のパターンを空にすることはできません。 +stdlib.command.grep.flags_not_string = grep のフラグは文字列でなければなりません。 +stdlib.command.quote.invalid = { $arg } を引用符で囲めませんでした: { $details }。 +stdlib.command.quote.line_break = 復帰または改行を含む引数は安全に引用符で囲めません。 +stdlib.command.input_undefined = 入力値が未定義です。 +stdlib.command.tempfile.root_required = コマンドの一時ファイルを作成するにはワークスペースのルートが必要です。 +stdlib.command.tempfile.create_failed = コマンドの一時ファイルを作成できませんでした: { $details }。 +stdlib.command.options.invalid_utf8 = コマンドオプションのキーは有効な UTF-8 でなければなりません。 +stdlib.command.option.mode_not_string = 出力モードは文字列でなければなりません。 +stdlib.command.options.invalid_type = コマンドのオプションはオブジェクトでなければなりません。 +stdlib.command.output.mode_unsupported = 対応していない出力モード「{ $mode }」です。 +stdlib.command.output.mode.capture = 取り込み +stdlib.command.output.mode.streaming = ストリーミング +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# パスヘルパーの診断。 +stdlib.path.io.failed = { $path } に対する「{ $action }」に失敗しました({ $label })。 +stdlib.path.io.failed_with_detail = { $path } に対する「{ $action }」に失敗しました: { $detail }。 +stdlib.path.io.failed_with_label_and_detail = { $path } に対する「{ $action }」に失敗しました({ $label }): { $detail }。 +stdlib.path.io.not_found = 見つかりません +stdlib.path.io.permission_denied = アクセスが拒否されました +stdlib.path.io.already_exists = すでに存在します +stdlib.path.io.invalid_input = 無効な入力 +stdlib.path.io.invalid_data = 無効なデータ +stdlib.path.io.timed_out = 時間切れ +stdlib.path.io.interrupted = 中断されました +stdlib.path.io.would_block = 処理が滞ります +stdlib.path.io.write_zero = 0 バイトの書き込み +stdlib.path.io.unexpected_eof = 予期しないファイル終端 +stdlib.path.io.broken_pipe = パイプの切断 +stdlib.path.io.connection_refused = 接続が拒否されました +stdlib.path.io.connection_reset = 接続がリセットされました +stdlib.path.io.connection_aborted = 接続が中断されました +stdlib.path.io.not_connected = 接続されていません +stdlib.path.io.addr_in_use = アドレスは使用中です +stdlib.path.io.addr_not_available = アドレスを利用できません +stdlib.path.io.out_of_memory = メモリー不足 +stdlib.path.io.unsupported = 対応していません +stdlib.path.io.file_too_large = ファイルが大きすぎます +stdlib.path.io.resource_busy = リソースが使用中です +stdlib.path.io.executable_busy = 実行ファイルが使用中です +stdlib.path.io.deadlock = デッドロック +stdlib.path.io.crosses_devices = デバイスをまたいでいます +stdlib.path.io.too_many_links = リンクが多すぎます +stdlib.path.io.invalid_filename = 無効なファイル名 +stdlib.path.io.arg_list_too_long = 引数リストが長すぎます +stdlib.path.io.stale_handle = 失効したネットワークファイルハンドル +stdlib.path.io.storage_full = 記憶領域がいっぱいです +stdlib.path.io.not_seekable = 位置指定ができません +stdlib.path.io.network_down = ネットワークが停止しています +stdlib.path.io.network_unreachable = ネットワークに到達できません +stdlib.path.io.host_unreachable = ホストに到達できません +stdlib.path.io.other = 入出力エラー +stdlib.path.action.canonicalize = 正準化 +stdlib.path.action.open_directory = ディレクトリーを開く操作 +stdlib.path.action.stat = 情報取得 +stdlib.path.action.read = 読み取り +stdlib.path.action.open_file = ファイルを開く操作 +stdlib.path.with_suffix.empty_separator = with_suffix には空でない区切り文字が必要です。 +stdlib.path.relative_to.mismatch = { $path } は { $root } からの相対パスではありません。 +stdlib.path.expanduser.unsupported = 特定ユーザーに対する ~ の展開には対応していません。 +stdlib.path.expanduser.no_home = ~ を展開できません。ホームディレクトリーの環境変数が設定されていません。 +stdlib.path.contents.unsupported_encoding = 対応していない文字符号化「{ $encoding }」です。 +stdlib.path.hash.unsupported_algorithm = 対応していないハッシュアルゴリズム「{ $algorithm }」です。 +stdlib.path.hash.unsupported_algorithm_legacy = 対応していないハッシュアルゴリズム「{ $algorithm }」です(機能「{ $feature }」を有効にしてください)。 + +# コレクションヘルパーの診断。 +stdlib.collections.flatten.expected_sequence = flatten は列の要素を期待しましたが、{ $kind } が見つかりました。 +stdlib.collections.group_by.empty_attribute = group_by には空でない属性が必要です。 +stdlib.collections.group_by.unresolved = group_by は種別 { $kind } の要素で「{ $attr }」を解決できませんでした。 + +# 時刻ヘルパーの診断。 +stdlib.time.offset.invalid = now のオフセット「{ $offset }」は無効です。「+HH:MM[:SS]」または「Z」が必要です。 +stdlib.time.timedelta.overflow = { $component } の加算で timedelta があふれました。 +stdlib.time.label.weeks = 週 +stdlib.time.label.days = 日 +stdlib.time.label.hours = 時間 +stdlib.time.label.minutes = 分 +stdlib.time.label.seconds = 秒 +stdlib.time.label.milliseconds = ミリ秒 +stdlib.time.label.microseconds = マイクロ秒 +stdlib.time.label.nanoseconds = ナノ秒 + +# which ヘルパーの診断。 +stdlib.which.not_found = [netsuke::jinja::which::not_found] PATH の項目を { $count } 件調べましたが、コマンド「{ $command }」は見つかりませんでした。プレビュー: { $preview } +stdlib.which.not_found.hint.cwd_auto = PATH の空の区間は無視されます。作業ディレクトリーを含めるには cwd_mode="auto" を使ってください。 +stdlib.which.not_found.hint.cwd_always = 現在のディレクトリーを含めるには cwd_mode="always" を設定してください。 +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] 「{ $path }」のコマンド「{ $command }」が存在しないか、実行できません。 +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = <空> +stdlib.which.path_entry.non_utf8 = PATH の { $index } 番目の項目に UTF-8 でない文字が含まれています。Netsuke は UTF-8 のパスを必要とします。 +stdlib.which.command.empty = which には空でない文字列が必要です。 +stdlib.which.cwd_mode.invalid = cwd_mode は「auto」「always」「never」のいずれかでなければなりませんが、「{ $mode }」が得られました。 +stdlib.which.cwd.resolve_failed = 現在のディレクトリーを特定できませんでした: { $details }。 +stdlib.which.cwd.non_utf8 = 現在のディレクトリーに UTF-8 でない部分が含まれています。 +stdlib.which.canonicalize_failed = 「{ $path }」を正準化できませんでした: { $details }。 +stdlib.which.is_executable = 「{ $path }」が実行可能かどうか調べられませんでした: { $details }。 +stdlib.which.canonicalize_non_utf8 = 正準パスに UTF-8 でない部分が含まれています。 +stdlib.which.workspace_non_utf8 = コマンド「{ $command }」の解決中、ワークスペースのパスに UTF-8 でない部分が含まれていました: { $path }。 +stdlib.which.walkdir_error = コマンドの解決中にワークスペースの走査でエラーが発生しました: { $details }。 + +# 標準ライブラリーの登録。 +stdlib.register.open_dir = stdlib の登録のために現在のディレクトリーを開けませんでした。 +stdlib.register.resolve_dir = stdlib の登録のために現在のディレクトリーを特定できませんでした。 +stdlib.register.dir_non_utf8 = 現在のディレクトリーに UTF-8 でない部分が含まれています: { $path }。 + +# アクセシブル出力モードの状態表示。 +status.state.pending = 待機中 +status.state.running = 進行中 +status.state.done = 完了 +status.state.failed = 失敗 +status.stage.label = 段階 { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label }({ $task_progress }) +status.task.progress_label = タスク { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = マニフェストファイルを読み取り中 +status.stage.initial_yaml_parsing = YAML 文書を解析中 +status.stage.template_expansion = テンプレート指令を展開中 +status.stage.final_rendering = マニフェストの値を復元して描画中 +status.stage.ir_generation_validation = 依存グラフを構築して検証中 +status.stage.ninja_synthesis = Ninja のビルド計画を合成中 +status.stage.ninja_synthesis_execute = Ninja の計画を合成し { $tool } を実行中 +status.stage.graph_rendering = グラフ成果物を描画中 +status.stage.graph_rendering_with_tool = { $tool } を描画中 +status.complete = { $tool } が完了しました。 +status.timing.summary_header = 段階ごとの所要時間: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = パイプライン全体の所要時間: { $duration } +status.tool.build = ビルド +status.tool.clean = クリーン +status.tool.graph = グラフ +status.tool.graph_html = グラフ(HTML) +status.tool.generate = 生成 + +# グラフの HTML 描画に使う文言。 +graph.html.title = Netsuke のビルドグラフ +graph.html.heading = Netsuke のビルドグラフ +graph.html.description = Netsuke が描画したビルドグラフ +graph.html.outline.summary = ターゲットと依存関係(テキストの概要) +graph.html.outline.no_inputs = 入力なし +graph.html.noscript.notice = JavaScript が無効です。上のテキスト概要がグラフ全体であり、続けて DOT のソースが表示されます。 + +# アクセシブル出力の意味づけ接頭辞。 +semantic.prefix.error = エラー: +semantic.prefix.warning = 警告: +semantic.prefix.success = 成功: +semantic.prefix.info = 情報: +semantic.prefix.timing = 所要時間: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# 翻訳者向けの複数形の例。 +# 日本語には文法上の複数形がないため、CLDR の分類は `other` だけです。 +example.files_processed = { $count -> + *[other] { $count } 件のファイルを処理しました。 +} + +example.errors_found = { $count -> + [0] エラーは見つかりませんでした。 + *[other] { $count } 件のエラーが見つかりました。 +} diff --git a/locales/ko/messages.ftl b/locales/ko/messages.ftl new file mode 100644 index 000000000..c06d4c386 --- /dev/null +++ b/locales/ko/messages.ftl @@ -0,0 +1,395 @@ +# Netsuke 명령줄의 지역화 리소스. + +cli.about = Netsuke는 YAML + Jinja 매니페스트를 Ninja 빌드 계획으로 컴파일합니다. +cli.long_about = Netsuke는 YAML + Jinja 매니페스트를 재현 가능한 Ninja 그래프로 변환한 뒤 안전한 기본값으로 Ninja를 실행합니다. +cli.usage = { $usage } + +# 전역 옵션의 도움말. +cli.flag.file.help = 사용할 Netsuke 매니페스트 파일의 경로입니다. +cli.flag.directory.help = 이 디렉터리에서 시작한 것처럼 실행합니다. +cli.flag.config.help = 자동 검색을 건너뛰고 사용할 설정 파일의 경로입니다. +cli.flag.jobs.help = 병렬로 실행할 빌드 작업 수를 지정합니다. +cli.flag.verbose.help = 상세 진단 로그와 완료 시점의 소요 시간 요약을 켭니다. +cli.flag.locale.help = 명령줄 문구의 로케일 태그입니다(예: en-US, ko). +cli.flag.fetch_allow_scheme.help = fetch 도우미에 추가로 허용할 URL 스킴입니다. +cli.flag.fetch_allow_host.help = 기본 거부가 켜져 있을 때 허용할 호스트 이름입니다. +cli.flag.fetch_block_host.help = 다른 곳에서 허용되더라도 항상 차단할 호스트 이름입니다. +cli.flag.fetch_default_deny.help = 기본적으로 모든 호스트를 거부하고 선언한 허용 목록만 통과시킵니다. +cli.flag.json.help = 기계가 읽을 수 있는 JSON을 출력합니다. +cli.flag.no_input.help = 대화형 입력을 절대 읽지 않습니다. +cli.flag.color.help = 색상 출력 정책(auto, always, never). +cli.flag.emoji.help = 이모지 정책(auto, always, never). +cli.flag.progress.help = 진행 상황 표시 정책(auto, always, never). +cli.flag.accessibility.help = 접근성 출력 정책(auto, on, off). +cli.flag.default_targets.help = 대상을 지정하지 않았을 때 사용할 기본 빌드 대상입니다. + +# 하위 명령 설명. +cli.subcommand.build.about = 매니페스트에 정의된 대상을 빌드합니다(기본값). +cli.subcommand.build.long_about = 요청한 대상을 빌드하며, 지정하지 않으면 매니페스트의 기본 대상을 사용합니다. +cli.subcommand.clean.about = Ninja를 통해 빌드 산출물을 제거합니다. +cli.subcommand.clean.long_about = 임시 Ninja 파일을 만든 뒤 `ninja -t clean`을 실행합니다. +cli.subcommand.graph.about = 빌드 의존성 그래프를 출력합니다. 기본 형식은 DOT입니다. +cli.subcommand.graph.long_about = 해석한 Netsuke 매니페스트를 정규 빌드 그래프로 투영해 Graphviz DOT으로, 또는 `--html`을 지정하면 자체 완결형 HTML 페이지로 씁니다. 파일로 쓰려면 `--output <파일>`을 사용하고, `-`는 표준 출력으로 씁니다. +cli.subcommand.generate.about = Ninja를 실행하지 않고 Ninja 매니페스트를 생성합니다. +cli.subcommand.generate.long_about = 생성한 Ninja 매니페스트를 표준 출력이나 `--output`으로 고른 파일에 씁니다. + +# build 하위 명령 옵션의 도움말. +cli.subcommand.build.flag.targets.help = 빌드할 대상입니다(생략하면 매니페스트의 기본값을 사용). + +# graph 하위 명령 옵션의 도움말. +cli.subcommand.graph.flag.html.help = 그래프를 DOT 대신 자체 완결형 HTML 페이지로 렌더링합니다. +cli.subcommand.graph.flag.output.help = 그래프 산출물을 파일에 씁니다. 표준 출력에는 `-`를 사용하세요. + +# generate 하위 명령 옵션의 도움말. +cli.subcommand.generate.flag.output.help = 생성한 Ninja 매니페스트를 표준 출력 대신 파일에 씁니다. + +# 명령줄 검증 오류. +cli.validation.jobs.invalid_number = { $value }은(는) 유효한 숫자가 아닙니다. +cli.validation.jobs.out_of_range = 작업 수는 { $min }에서 { $max } 사이여야 합니다. +cli.validation.scheme.empty = 스킴은 비어 있을 수 없습니다. +cli.validation.scheme.invalid_start = 스킴 '{ $scheme }'은(는) ASCII 문자로 시작해야 합니다. +cli.validation.scheme.invalid = 잘못된 스킴 '{ $scheme }'입니다. +cli.validation.locale.empty = 로케일 태그는 비어 있을 수 없습니다. +cli.validation.locale.invalid = 잘못된 로케일 태그 '{ $locale }'입니다. +cli.validation.color.invalid = 잘못된 색상 정책 '{ $value }'입니다. 유효한 값: auto, always, never. +cli.validation.emoji.invalid = 잘못된 이모지 정책 '{ $value }'입니다. 유효한 값: auto, always, never. +cli.validation.progress.invalid = 잘못된 진행 상황 정책 '{ $value }'입니다. 유효한 값: auto, always, never. +cli.validation.accessibility.invalid = 잘못된 접근성 정책 '{ $value }'입니다. 유효한 값: auto, on, off. +cli.validation.config.expected_object = 명령줄 값이 객체로 직렬화되어야 하지만 { $value }이(가) 나왔습니다. + +# Clap 오류 메시지. +clap-error-missing-argument = 필수 인자가 없습니다: { $argument } +clap-error-missing-subcommand = 하위 명령이 없습니다. 사용할 수 있는 값: { $valid_subcommands } +clap-error-unknown-argument = 알 수 없는 인자입니다: { $argument } +clap-error-invalid-value = { $argument }의 값이 잘못되었습니다: { $value } +clap-error-invalid-subcommand = 알 수 없는 하위 명령입니다: { $subcommand } +# 참고: value-validation은 사용자 정의 검증기의 실패(ErrorKind::ValueValidation)를 +# 형식 불일치(ErrorKind::InvalidValue)와 구분하기 위해 invalid-value와 다르게 +# 표현했습니다. +clap-error-value-validation = { $argument }의 검증에 실패했습니다: { $value } + +# 실행 중 오류와 맥락. +runner.manifest.not_found = 매니페스트 '{ $manifest_name }'을(를) { $directory }에서 찾을 수 없습니다. +runner.manifest.not_found.help = 매니페스트가 있는지 확인하거나 올바른 경로로 `--file`을 지정하세요. +runner.manifest.path_missing_name = 매니페스트 경로 '{ $path }'에 파일 이름이 없습니다. +runner.manifest.path_utf8 = 매니페스트 경로 '{ $path }'은(는) 올바른 UTF-8이 아닙니다. +runner.manifest.directory_utf8 = 매니페스트 디렉터리 경로 '{ $path }'은(는) 올바른 UTF-8이 아닙니다. +runner.manifest.directory_label = `{ $directory }` 디렉터리 +runner.manifest.current_directory_label = 현재 디렉터리 +runner.context.network_policy = 네트워크 정책을 구성하지 못했습니다. +runner.context.load_manifest = { $path }의 매니페스트를 불러오지 못했습니다. +runner.context.serialise_manifest = 매니페스트를 직렬화하지 못했습니다. +runner.context.build_graph = 매니페스트로 그래프를 구성하지 못했습니다. +runner.context.generate_ninja = Ninja 매니페스트를 생성하지 못했습니다. +runner.context.render_graph = 그래프 산출물을 렌더링하지 못했습니다. + +runner.io.create_temp_file = 임시 Ninja 파일을 만들지 못했습니다. +runner.io.write_temp_ninja = 임시 Ninja 파일에 쓰지 못했습니다. +runner.io.flush_temp_ninja = 임시 Ninja 파일의 버퍼를 비우지 못했습니다. +runner.io.sync_temp_ninja = 임시 Ninja 파일을 동기화하지 못했습니다. +runner.io.create_parent_dir = 상위 디렉터리 { $path }을(를) 만들지 못했습니다. +runner.io.create_ninja_file = { $path }에 Ninja 파일을 만들지 못했습니다. +runner.io.write_ninja_file = { $path }의 Ninja 파일에 쓰지 못했습니다. +runner.io.flush_ninja_file = { $path }의 Ninja 파일 버퍼를 비우지 못했습니다. +runner.io.sync_ninja_file = { $path }의 Ninja 파일을 동기화하지 못했습니다. +runner.io.open_ambient_dir = 주변 디렉터리를 열지 못했습니다. +runner.io.no_existing_ancestor = { $path }에 해당하는 상위 디렉터리가 없습니다. +runner.io.derive_relative_path = 상대 Ninja 경로를 유도하지 못했습니다. +runner.io.non_utf8_path = UTF-8이 아닌 경로는 지원하지 않습니다(경로: { $path }). +runner.io.write_stdout = Ninja 매니페스트를 표준 출력에 쓰지 못했습니다. +runner.io.flush_stdout = 표준 출력의 버퍼를 비우지 못했습니다. + +# 매니페스트 진단. +manifest.parse = 매니페스트 해석에 실패했습니다. +manifest.structure_error = { $name }에서 매니페스트 구조 오류: { $details } +manifest.yaml.parse = { $line }행 { $column }열에서 YAML 해석 오류: { $details } +manifest.yaml.label = 잘못된 YAML +manifest.yaml.hint.tabs = YAML은 탭을 허용하지 않습니다. 들여쓰기에는 공백을 사용하세요. +manifest.yaml.hint.list_item = YAML 목록 항목은 '-'로 시작하고 올바르게 들여써야 합니다. +manifest.yaml.hint.expected_colon = 매핑 항목으로 보입니다. 키 뒤에 ':'이 없습니다. +manifest.yaml.hint.mapping_values = YAML 매핑은 ':' 뒤에 값(또는 중첩 블록)이 필요합니다. +manifest.yaml.hint.invalid_token = YAML 토큰이 잘못되었거나 예상 밖입니다. +manifest.yaml.hint.escape = 역슬래시를 이스케이프하거나 잘못된 이스케이프 시퀀스를 제거하세요. +manifest.env.missing = 필수 환경 변수 '{ $name }'이(가) 설정되지 않았습니다. +manifest.env.invalid_utf8 = 환경 변수 '{ $name }'에 잘못된 UTF-8이 들어 있습니다. +manifest.vars.not_object = 매니페스트의 `vars`는 매핑이나 객체여야 합니다. +manifest.read_failed = { $path }의 매니페스트를 읽지 못했습니다. +manifest.resolve_workspace_root = 작업 공간의 루트를 확인하지 못했습니다. +manifest.workspace_non_utf8 = 작업 공간의 루트 경로 '{ $path }'은(는) 올바른 UTF-8이 아닙니다. +manifest.path_non_utf8 = 매니페스트 '{ $manifest }'의 경로가 올바른 UTF-8이 아닙니다: { $path }. +manifest.path_missing_name = 매니페스트 경로 '{ $path }'에 파일 이름이 없습니다. +manifest.open_workspace_failed = 매니페스트 { $manifest }을(를) 위해 작업 공간 { $workspace }을(를) 열지 못했습니다. +manifest.foreach.not_iterable = `foreach` 식은 순회할 수 없습니다. +manifest.foreach.serialise_item = `foreach`의 항목을 직렬화하지 못했습니다. +manifest.when.empty = `when` 식은 비어 있을 수 없습니다. +manifest.when.eval_error = `when` 식 '{ $expr }'을(를) 평가하지 못했습니다. +manifest.when.template_error = `when` 템플릿 '{ $expr }'을(를) 렌더링하지 못했습니다. +manifest.target.vars_not_object = 대상의 `vars`는 객체여야 하지만 { $value }이(가) 나왔습니다. +manifest.vars.entry_not_object = 매니페스트의 `vars` 항목은 객체여야 합니다. +manifest.field_not_string = '{ $field }' 필드는 문자열이어야 합니다. +manifest.expression.parse_error = { $name } 식을 해석하지 못했습니다. +manifest.expression.eval_error = { $name } 식을 평가하지 못했습니다. + +# 매니페스트 매크로 진단. +manifest.macro.signature_missing_identifier = 매크로 시그니처에 식별자가 없습니다. +manifest.macro.signature_missing_params = 매크로 시그니처에 매개변수가 없습니다. +manifest.macro.compile_failed = 매크로 { $name }을(를) 컴파일하지 못했습니다. +manifest.macro.sequence_invalid = 매크로는 이름에서 템플릿으로의 매핑으로 정의해야 합니다. +manifest.macro.register_failed = 매니페스트의 매크로를 등록하지 못했습니다. +manifest.macro.not_initialised = 매크로 환경이 초기화되지 않았습니다. +manifest.macro.caller_invalid = 매크로 호출자는 문자열이어야 합니다. +manifest.macro.template_load_failed = 매크로 템플릿을 불러오지 못했습니다. +manifest.macro.init_failed = 매크로 환경을 초기화하지 못했습니다. +manifest.macro.missing = 매크로 { $name }이(가) 없습니다. + +# 매니페스트 glob 오류. +manifest.glob.unmatched_brace = 잘못된 glob 패턴 '{ $pattern }': { $position } 위치의 '{ $character }'에 짝이 없습니다. +manifest.glob.invalid_pattern = 잘못된 glob 패턴 '{ $pattern }': { $detail }. +manifest.glob.unknown_pattern_error = 알 수 없는 패턴 오류. +manifest.glob.io_failed = '{ $pattern }'에 대한 glob이 실패했습니다: { $detail }. +manifest.glob.unknown_io_error = 알 수 없는 입출력 오류. + +# 중간 표현 오류. +ir.rule_not_found = 대상 '{ $target }'이(가) 참조하는 규칙 '{ $rule }'을(를) 찾을 수 없습니다. +ir.multiple_rules = 대상 '{ $target }'은(는) 규칙 하나만 참조해야 하지만 { $rules }이(가) 나왔습니다. +ir.empty_rule = 대상 '{ $target }'은(는) 규칙을 참조해야 합니다. +ir.duplicate_outputs = 중복된 출력이 발견되었습니다: { $outputs }. +ir.circular_dependency = 순환 의존성이 발견되었습니다: { $cycle }. +ir.action_serialisation = 동작을 직렬화하지 못했습니다: { $details }. +ir.invalid_command = 명령의 보간이 잘못되었습니다: { $snippet }. + +# Ninja 생성 오류. +ninja_gen.missing_action = 빌드 간선이 참조하는 동작 '{ $id }'이(가) 없습니다. +ninja_gen.format = Ninja 매니페스트 출력의 서식을 지정하지 못했습니다. + +# 호스트 패턴 검증. +host_pattern.empty = 호스트 패턴은 비어 있을 수 없습니다. +host_pattern.contains_scheme = 호스트 패턴 '{ $pattern }'에는 URL 스킴이 들어갈 수 없습니다. +host_pattern.contains_slash = 호스트 패턴 '{ $pattern }'에는 '/'가 들어갈 수 없습니다. +host_pattern.missing_suffix = 호스트 패턴 '{ $pattern }'에는 '*.' 뒤에 접미사가 있어야 합니다. +host_pattern.empty_label = 호스트 패턴 '{ $pattern }'에 빈 레이블이 있습니다. +host_pattern.invalid_chars = 호스트 패턴 '{ $pattern }'에 잘못된 문자가 있습니다. +host_pattern.invalid_label_edge = 호스트 패턴 '{ $pattern }'의 레이블은 '-'로 시작하거나 끝날 수 없습니다. +host_pattern.label_too_long = 호스트 패턴 '{ $pattern }'에 63자를 넘는 레이블이 있습니다. +host_pattern.too_long = 호스트 패턴 '{ $pattern }'이(가) 255자 제한을 넘습니다. + +# 네트워크 정책. +network_policy.scheme.empty = 스킴은 비어 있을 수 없습니다. +network_policy.scheme.invalid = 스킴 '{ $scheme }'에 잘못된 문자가 있습니다. +network_policy.allowlist.empty = 호스트 허용 목록은 비어 있을 수 없습니다. +network_policy.scheme.not_allowed = 스킴 '{ $scheme }'은(는) 허용되지 않습니다. +network_policy.missing_host = URL에 호스트가 없습니다. +network_policy.host.blocked = 호스트 '{ $host }'은(는) 정책에 의해 차단되었습니다. +network_policy.host.not_allowlisted = 호스트 '{ $host }'은(는) 허용 목록에 없습니다. + +# 표준 라이브러리 설정. +stdlib.config.default_fetch_cache_invalid = fetch 캐시의 기본 경로는 상대 경로여야 합니다. +stdlib.config.default_which_cache_invalid = which 캐시의 기본 용량은 양수여야 합니다. +stdlib.config.workspace_root_absolute = 작업 공간의 루트 경로는 절대 경로여야 합니다. +stdlib.config.fetch_response_limit_positive = fetch의 응답 한도는 양수여야 합니다. +stdlib.config.command_output_limit_positive = 명령 출력의 수집 한도는 양수여야 합니다. +stdlib.config.command_stream_limit_positive = 명령의 스트림 한도는 양수여야 합니다. +stdlib.config.which_cache_capacity_positive = which 캐시의 용량은 양수여야 합니다. +stdlib.config.skip_dir_empty = 건너뛸 디렉터리 항목은 비어 있을 수 없습니다. +stdlib.config.skip_dir_navigation = 건너뛸 디렉터리 항목에는 '..'이 들어갈 수 없습니다. +stdlib.config.skip_dir_separator = 건너뛸 디렉터리 항목에는 경로 구분자가 들어갈 수 없습니다. +stdlib.config.fetch_cache_empty = fetch 캐시의 경로는 비어 있을 수 없습니다. +stdlib.config.fetch_cache_not_relative = fetch 캐시의 경로는 상대 경로여야 하지만 { $path }이(가) 나왔습니다. +stdlib.config.fetch_cache_escapes = fetch 캐시의 경로는 작업 공간을 벗어날 수 없습니다: { $path }. +stdlib.config.open_workspace_root = 현재 디렉터리를 stdlib 작업 공간의 루트로 열지 못했습니다. +stdlib.config.resolve_cwd = 현재 디렉터리를 stdlib 작업 공간의 루트로 확인하지 못했습니다. +stdlib.config.cwd_non_utf8 = 현재 디렉터리에 UTF-8이 아닌 부분이 있습니다: { $path }. + +# fetch 도우미 진단. +stdlib.fetch.url_invalid = 잘못된 URL '{ $url }': { $details }. +stdlib.fetch.disallowed = URL '{ $url }'은(는) 허용되지 않습니다: { $details }. +stdlib.fetch.failed = '{ $url }'을(를) 가져오지 못했습니다: { $details }. +stdlib.fetch.cache_read_failed = 캐시 항목 '{ $name }'을(를) 읽지 못했습니다: { $details }. +stdlib.fetch.cache_open_failed = 캐시 항목 '{ $name }'을(를) 열지 못했습니다: { $details }. +stdlib.fetch.response_read_failed = '{ $url }'의 응답을 읽지 못했습니다: { $details }. +stdlib.fetch.response_buffer_overflow = '{ $url }'을(를) 읽는 중 버퍼가 넘쳤습니다. +stdlib.fetch.cache_write_failed = '{ $url }'의 캐시를 쓰지 못했습니다: { $details }. +stdlib.fetch.response_limit_exceeded = '{ $url }'의 응답이 { $limit }바이트 한도를 넘었습니다. +stdlib.fetch.cache_limit_exceeded = 캐시된 응답 '{ $name }'이(가) { $limit }바이트 한도를 넘었습니다. +stdlib.fetch.io_failed = { $path }에 대한 '{ $action }'에 실패했습니다: { $details }. +stdlib.fetch.action.sync_cache = fetch 캐시 동기화 +stdlib.fetch.action.create_cache_dir = fetch 캐시 디렉터리 생성 +stdlib.fetch.action.open_cache_dir = fetch 캐시 디렉터리 열기 +stdlib.fetch.action.stat_cache = fetch 캐시 항목 정보 조회 +stdlib.fetch.action.open_cache_entry = fetch 캐시 항목 열기 + +# 명령 도우미 진단. +stdlib.command.location = 템플릿 '{ $template }'의 명령 '{ $command }' +stdlib.command.spawn_failed = { $location }을(를) 시작하지 못했습니다: { $details }. +stdlib.command.io_failed = { $location }이(가) 실패했습니다: { $details }. +stdlib.command.closed_input_early = 명령에 쓰기가 끝나기 전에 입력이 닫혔습니다. +stdlib.command.broken_pipe = { $location } 실행 중 파이프가 끊겼습니다: { $details }. +stdlib.command.terminated_by_signal = { $location }이(가) 신호로 종료되었습니다. +stdlib.command.exited_with_status = { $location }이(가) 상태 { $status }(으)로 끝났습니다. +stdlib.command.output_limit_exceeded = { $location }이(가) { $stream }에 대한 { $mode } 한도 { $limit }바이트를 넘었습니다. +stdlib.command.timeout = { $location }이(가) { $seconds }초 제한 시간을 넘었습니다. +stdlib.command.exit_status_suffix = (종료 상태 { $status }) +stdlib.command.signal_suffix = (신호로 종료됨) +stdlib.command.shell.empty = 셸 명령은 비어 있을 수 없습니다. +stdlib.command.grep.empty_pattern = grep 패턴은 비어 있을 수 없습니다. +stdlib.command.grep.flags_not_string = grep 플래그는 문자열이어야 합니다. +stdlib.command.quote.invalid = { $arg }을(를) 따옴표로 감싸지 못했습니다: { $details }. +stdlib.command.quote.line_break = 캐리지 리턴이나 줄바꿈이 들어 있는 인자는 안전하게 따옴표로 감쌀 수 없습니다. +stdlib.command.input_undefined = 입력 값이 정의되지 않았습니다. +stdlib.command.tempfile.root_required = 명령의 임시 파일을 만들려면 작업 공간의 루트가 필요합니다. +stdlib.command.tempfile.create_failed = 명령의 임시 파일을 만들지 못했습니다: { $details }. +stdlib.command.options.invalid_utf8 = 명령 옵션의 키는 올바른 UTF-8이어야 합니다. +stdlib.command.option.mode_not_string = 출력 모드는 문자열이어야 합니다. +stdlib.command.options.invalid_type = 명령 옵션은 객체여야 합니다. +stdlib.command.output.mode_unsupported = 지원하지 않는 출력 모드 '{ $mode }'입니다. +stdlib.command.output.mode.capture = 수집 +stdlib.command.output.mode.streaming = 스트리밍 +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# 경로 도우미 진단. +stdlib.path.io.failed = { $path }에 대한 '{ $action }'에 실패했습니다({ $label }). +stdlib.path.io.failed_with_detail = { $path }에 대한 '{ $action }'에 실패했습니다: { $detail }. +stdlib.path.io.failed_with_label_and_detail = { $path }에 대한 '{ $action }'에 실패했습니다({ $label }): { $detail }. +stdlib.path.io.not_found = 찾을 수 없음 +stdlib.path.io.permission_denied = 권한 거부됨 +stdlib.path.io.already_exists = 이미 있음 +stdlib.path.io.invalid_input = 잘못된 입력 +stdlib.path.io.invalid_data = 잘못된 데이터 +stdlib.path.io.timed_out = 시간 초과 +stdlib.path.io.interrupted = 중단됨 +stdlib.path.io.would_block = 차단될 수 있음 +stdlib.path.io.write_zero = 0바이트 기록 +stdlib.path.io.unexpected_eof = 예상치 못한 파일 끝 +stdlib.path.io.broken_pipe = 파이프 끊김 +stdlib.path.io.connection_refused = 연결 거부됨 +stdlib.path.io.connection_reset = 연결 재설정됨 +stdlib.path.io.connection_aborted = 연결 중단됨 +stdlib.path.io.not_connected = 연결되지 않음 +stdlib.path.io.addr_in_use = 주소가 사용 중 +stdlib.path.io.addr_not_available = 주소를 사용할 수 없음 +stdlib.path.io.out_of_memory = 메모리 부족 +stdlib.path.io.unsupported = 지원하지 않음 +stdlib.path.io.file_too_large = 파일이 너무 큼 +stdlib.path.io.resource_busy = 자원이 사용 중 +stdlib.path.io.executable_busy = 실행 파일이 사용 중 +stdlib.path.io.deadlock = 교착 상태 +stdlib.path.io.crosses_devices = 장치를 넘나듦 +stdlib.path.io.too_many_links = 링크가 너무 많음 +stdlib.path.io.invalid_filename = 잘못된 파일 이름 +stdlib.path.io.arg_list_too_long = 인자 목록이 너무 김 +stdlib.path.io.stale_handle = 오래된 네트워크 파일 핸들 +stdlib.path.io.storage_full = 저장 공간이 가득 참 +stdlib.path.io.not_seekable = 위치를 지정할 수 없음 +stdlib.path.io.network_down = 네트워크가 작동하지 않음 +stdlib.path.io.network_unreachable = 네트워크에 도달할 수 없음 +stdlib.path.io.host_unreachable = 호스트에 도달할 수 없음 +stdlib.path.io.other = 입출력 오류 +stdlib.path.action.canonicalize = 정규화 +stdlib.path.action.open_directory = 디렉터리 열기 +stdlib.path.action.stat = 정보 조회 +stdlib.path.action.read = 읽기 +stdlib.path.action.open_file = 파일 열기 +stdlib.path.with_suffix.empty_separator = with_suffix에는 비어 있지 않은 구분자가 필요합니다. +stdlib.path.relative_to.mismatch = { $path }은(는) { $root }에 대한 상대 경로가 아닙니다. +stdlib.path.expanduser.unsupported = 특정 사용자에 대한 ~ 확장은 지원하지 않습니다. +stdlib.path.expanduser.no_home = ~을(를) 확장할 수 없습니다. 홈 디렉터리 환경 변수가 설정되지 않았습니다. +stdlib.path.contents.unsupported_encoding = 지원하지 않는 인코딩 '{ $encoding }'입니다. +stdlib.path.hash.unsupported_algorithm = 지원하지 않는 해시 알고리즘 '{ $algorithm }'입니다. +stdlib.path.hash.unsupported_algorithm_legacy = 지원하지 않는 해시 알고리즘 '{ $algorithm }'입니다('{ $feature }' 기능을 켜세요). + +# 컬렉션 도우미 진단. +stdlib.collections.flatten.expected_sequence = flatten은 열의 항목을 기대했지만 { $kind }을(를) 발견했습니다. +stdlib.collections.group_by.empty_attribute = group_by에는 비어 있지 않은 속성이 필요합니다. +stdlib.collections.group_by.unresolved = group_by가 { $kind } 형식의 항목에서 '{ $attr }'을(를) 찾지 못했습니다. + +# 시간 도우미 진단. +stdlib.time.offset.invalid = now의 오프셋 '{ $offset }'이(가) 잘못되었습니다. '+HH:MM[:SS]' 또는 'Z'가 필요합니다. +stdlib.time.timedelta.overflow = { $component }을(를) 더하는 중 timedelta가 넘쳤습니다. +stdlib.time.label.weeks = 주 +stdlib.time.label.days = 일 +stdlib.time.label.hours = 시간 +stdlib.time.label.minutes = 분 +stdlib.time.label.seconds = 초 +stdlib.time.label.milliseconds = 밀리초 +stdlib.time.label.microseconds = 마이크로초 +stdlib.time.label.nanoseconds = 나노초 + +# which 도우미 진단. +stdlib.which.not_found = [netsuke::jinja::which::not_found] PATH 항목 { $count }개를 확인했지만 명령 '{ $command }'을(를) 찾지 못했습니다. 미리 보기: { $preview } +stdlib.which.not_found.hint.cwd_auto = PATH의 빈 구간은 무시됩니다. 작업 디렉터리를 포함하려면 cwd_mode="auto"를 사용하세요. +stdlib.which.not_found.hint.cwd_always = 현재 디렉터리를 포함하려면 cwd_mode="always"로 설정하세요. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] '{ $path }'의 명령 '{ $command }'이(가) 없거나 실행할 수 없습니다. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = <비어 있음> +stdlib.which.path_entry.non_utf8 = PATH의 { $index }번째 항목에 UTF-8이 아닌 문자가 있습니다. Netsuke는 UTF-8 경로가 필요합니다. +stdlib.which.command.empty = which에는 비어 있지 않은 문자열이 필요합니다. +stdlib.which.cwd_mode.invalid = cwd_mode는 'auto', 'always', 'never' 중 하나여야 하지만 '{ $mode }'이(가) 나왔습니다. +stdlib.which.cwd.resolve_failed = 현재 디렉터리를 확인하지 못했습니다: { $details }. +stdlib.which.cwd.non_utf8 = 현재 디렉터리에 UTF-8이 아닌 부분이 있습니다. +stdlib.which.canonicalize_failed = '{ $path }'을(를) 정규화하지 못했습니다: { $details }. +stdlib.which.is_executable = '{ $path }'이(가) 실행 가능한지 확인하지 못했습니다: { $details }. +stdlib.which.canonicalize_non_utf8 = 정규 경로에 UTF-8이 아닌 부분이 있습니다. +stdlib.which.workspace_non_utf8 = 명령 '{ $command }'을(를) 해석하는 중 작업 공간 경로에 UTF-8이 아닌 부분이 있습니다: { $path }. +stdlib.which.walkdir_error = 명령을 해석하는 중 작업 공간을 순회하다 오류가 발생했습니다: { $details }. + +# 표준 라이브러리 등록. +stdlib.register.open_dir = stdlib 등록을 위해 현재 디렉터리를 열지 못했습니다. +stdlib.register.resolve_dir = stdlib 등록을 위해 현재 디렉터리를 확인하지 못했습니다. +stdlib.register.dir_non_utf8 = 현재 디렉터리에 UTF-8이 아닌 부분이 있습니다: { $path }. + +# 접근성 출력 모드의 상태 보고. +status.state.pending = 대기 중 +status.state.running = 진행 중 +status.state.done = 완료 +status.state.failed = 실패 +status.stage.label = 단계 { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = 작업 { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = 매니페스트 파일 읽는 중 +status.stage.initial_yaml_parsing = YAML 문서 해석 중 +status.stage.template_expansion = 템플릿 지시문 확장 중 +status.stage.final_rendering = 매니페스트 값 역직렬화 및 렌더링 중 +status.stage.ir_generation_validation = 의존성 그래프 구성 및 검증 중 +status.stage.ninja_synthesis = Ninja 빌드 계획 합성 중 +status.stage.ninja_synthesis_execute = Ninja 계획 합성 및 { $tool } 실행 중 +status.stage.graph_rendering = 그래프 산출물 렌더링 중 +status.stage.graph_rendering_with_tool = { $tool } 렌더링 중 +status.complete = { $tool } 작업이 완료되었습니다. +status.timing.summary_header = 단계별 소요 시간 요약: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = 파이프라인 전체 소요 시간: { $duration } +status.tool.build = 빌드 +status.tool.clean = 정리 +status.tool.graph = 그래프 +status.tool.graph_html = 그래프(HTML) +status.tool.generate = 생성 + +# 그래프 HTML 렌더러의 문구. +graph.html.title = Netsuke 빌드 그래프 +graph.html.heading = Netsuke 빌드 그래프 +graph.html.description = Netsuke가 렌더링한 빌드 그래프 +graph.html.outline.summary = 대상과 의존성(텍스트 개요) +graph.html.outline.no_inputs = 입력 없음 +graph.html.noscript.notice = JavaScript가 꺼져 있습니다. 위의 텍스트 개요가 그래프 전체이며, 이어서 DOT 원본이 나옵니다. + +# 접근성 출력의 의미 접두어. +semantic.prefix.error = 오류: +semantic.prefix.warning = 경고: +semantic.prefix.success = 성공: +semantic.prefix.info = 정보: +semantic.prefix.timing = 소요 시간: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# 번역자를 위한 복수형 예시. +# 한국어에는 문법적 복수 변화가 없으므로 CLDR 분류는 `other` 하나뿐입니다. +example.files_processed = { $count -> + *[other] 파일 { $count }개를 처리했습니다. +} + +example.errors_found = { $count -> + [0] 오류를 찾지 못했습니다. + *[other] 오류 { $count }개를 찾았습니다. +} diff --git a/locales/nb/messages.ftl b/locales/nb/messages.ftl new file mode 100644 index 000000000..00827d87c --- /dev/null +++ b/locales/nb/messages.ftl @@ -0,0 +1,397 @@ +# Lokaliseringsressurser for kommandolinjen til Netsuke (bokmål). + +cli.about = Netsuke kompilerer YAML- + Jinja-manifester til Ninja-byggeplaner. +cli.long_about = Netsuke gjør YAML- + Jinja-manifester om til reproduserbare Ninja-grafer og kjører Ninja med trygge standardverdier. +cli.usage = { $usage } + +# Hjelpetekst for globale valg. +cli.flag.file.help = Sti til Netsuke-manifestfilen som skal brukes. +cli.flag.directory.help = Kjør som om starten skjedde i denne katalogen. +cli.flag.config.help = Sti til en konfigurasjonsfil, utenom det automatiske søket. +cli.flag.jobs.help = Angi antallet parallelle byggejobber. +cli.flag.verbose.help = Slå på utførlig diagnoselogging og tidsoppsummeringer ved avslutning. +cli.flag.locale.help = Språkmerke for tekstene på kommandolinjen (for eksempel: en-US, nb). +cli.flag.fetch_allow_scheme.help = Flere URL-skjemaer som fetch-hjelperen kan bruke. +cli.flag.fetch_allow_host.help = Vertsnavn som tillates når standardavslaget er slått på. +cli.flag.fetch_block_host.help = Vertsnavn som alltid blokkeres, selv om de tillates andre steder. +cli.flag.fetch_default_deny.help = Avvis alle verter som standard; tillat bare den oppgitte listen. +cli.flag.json.help = Skriv ut maskinlesbar JSON. +cli.flag.no_input.help = Les aldri interaktive inndata. +cli.flag.color.help = Regel for farget utdata (auto, always, never). +cli.flag.emoji.help = Regel for emoji (auto, always, never). +cli.flag.progress.help = Regel for visning av framdrift (auto, always, never). +cli.flag.accessibility.help = Regel for tilgjengelig utdata (auto, on, off). +cli.flag.default_targets.help = Standardmål for byggingen når ingen er oppgitt. + +# Beskrivelser av underkommandoer. +cli.subcommand.build.about = Bygg målene som er definert i manifestet (standard). +cli.subcommand.build.long_about = Bygg de forespurte målene; er ingen oppgitt, brukes standardmålene fra manifestet. +cli.subcommand.clean.about = Fjern byggeartefakter via Ninja. +cli.subcommand.clean.long_about = Lag en midlertidig Ninja-fil og kjør deretter `ninja -t clean`. +cli.subcommand.graph.about = Skriv ut avhengighetsgrafen for byggingen. Standardformatet er DOT. +cli.subcommand.graph.long_about = Overfør det innleste Netsuke-manifestet til en kanonisk byggegraf og skriv den som Graphviz DOT, eller som en frittstående HTML-side med `--html`. Bruk `--output ` for å skrive til en fil; `-` skriver til stdout. +cli.subcommand.generate.about = Lag Ninja-manifestet uten å kjøre Ninja. +cli.subcommand.generate.long_about = Skriv det genererte Ninja-manifestet til stdout eller til en fil valgt med `--output`. + +# Hjelpetekst for valg til underkommandoen build. +cli.subcommand.build.flag.targets.help = Mål som skal bygges (bruker standardmålene fra manifestet hvis utelatt). + +# Hjelpetekst for valg til underkommandoen graph. +cli.subcommand.graph.flag.html.help = Gjengi grafen som en frittstående HTML-side i stedet for DOT. +cli.subcommand.graph.flag.output.help = Skriv grafartefaktet til FIL; bruk `-` for stdout. + +# Hjelpetekst for valg til underkommandoen generate. +cli.subcommand.generate.flag.output.help = Skriv det genererte Ninja-manifestet til FIL i stedet for stdout. + +# Valideringsfeil på kommandolinjen. +cli.validation.jobs.invalid_number = { $value } er ikke et gyldig tall. +cli.validation.jobs.out_of_range = Antallet jobber må ligge mellom { $min } og { $max }. +cli.validation.scheme.empty = Skjemaet kan ikke være tomt. +cli.validation.scheme.invalid_start = Skjemaet «{ $scheme }» må begynne med en ASCII-bokstav. +cli.validation.scheme.invalid = Ugyldig skjema «{ $scheme }». +cli.validation.locale.empty = Språkmerket kan ikke være tomt. +cli.validation.locale.invalid = Ugyldig språkmerke «{ $locale }». +cli.validation.color.invalid = Ugyldig fargeregel «{ $value }». Gyldige valg: auto, always, never. +cli.validation.emoji.invalid = Ugyldig emojiregel «{ $value }». Gyldige valg: auto, always, never. +cli.validation.progress.invalid = Ugyldig framdriftsregel «{ $value }». Gyldige valg: auto, always, never. +cli.validation.accessibility.invalid = Ugyldig tilgjengelighetsregel «{ $value }». Gyldige valg: auto, on, off. +cli.validation.config.expected_object = Verdiene fra kommandolinjen skulle serialiseres til et objekt, men ga { $value }. + +# Feilmeldinger fra Clap. +clap-error-missing-argument = Mangler påkrevd argument: { $argument } +clap-error-missing-subcommand = Mangler underkommando. Tilgjengelige valg: { $valid_subcommands } +clap-error-unknown-argument = Ukjent argument: { $argument } +clap-error-invalid-value = Ugyldig verdi for { $argument }: { $value } +clap-error-invalid-subcommand = Ukjent underkommando: { $subcommand } +# Merk: value-validation er formulert annerledes enn invalid-value for å skille +# feil fra egne validatorer (ErrorKind::ValueValidation) fra typekonflikter +# (ErrorKind::InvalidValue). +clap-error-value-validation = Valideringen mislyktes for { $argument }: { $value } + +# Feil og sammenheng fra kjøringen. +runner.manifest.not_found = Manifestet «{ $manifest_name }» ble ikke funnet i { $directory }. +runner.manifest.not_found.help = Kontroller at manifestet finnes, eller oppgi `--file` med riktig sti. +runner.manifest.path_missing_name = Manifeststien «{ $path }» mangler filnavn. +runner.manifest.path_utf8 = Manifeststien «{ $path }» er ikke gyldig UTF-8. +runner.manifest.directory_utf8 = Stien til manifestkatalogen «{ $path }» er ikke gyldig UTF-8. +runner.manifest.directory_label = katalogen `{ $directory }` +runner.manifest.current_directory_label = gjeldende katalog +runner.context.network_policy = Nettverksregelen kunne ikke bygges. +runner.context.load_manifest = Manifestet i { $path } kunne ikke lastes inn. +runner.context.serialise_manifest = Manifestet kunne ikke serialiseres. +runner.context.build_graph = Grafen kunne ikke bygges ut fra manifestet. +runner.context.generate_ninja = Ninja-manifestet kunne ikke lages. +runner.context.render_graph = Grafartefaktet kunne ikke gjengis. + +runner.io.create_temp_file = Den midlertidige Ninja-filen kunne ikke opprettes. +runner.io.write_temp_ninja = Den midlertidige Ninja-filen kunne ikke skrives. +runner.io.flush_temp_ninja = Bufferen for den midlertidige Ninja-filen kunne ikke tømmes. +runner.io.sync_temp_ninja = Den midlertidige Ninja-filen kunne ikke synkroniseres. +runner.io.create_parent_dir = Overkatalogen { $path } kunne ikke opprettes. +runner.io.create_ninja_file = Ninja-filen i { $path } kunne ikke opprettes. +runner.io.write_ninja_file = Ninja-filen i { $path } kunne ikke skrives. +runner.io.flush_ninja_file = Bufferen for Ninja-filen i { $path } kunne ikke tømmes. +runner.io.sync_ninja_file = Ninja-filen i { $path } kunne ikke synkroniseres. +runner.io.open_ambient_dir = Den omgivende katalogen kunne ikke åpnes. +runner.io.no_existing_ancestor = Det finnes ingen overordnet katalog for { $path }. +runner.io.derive_relative_path = Den relative Ninja-stien kunne ikke utledes. +runner.io.non_utf8_path = Stier som ikke er UTF-8, støttes ikke (sti: { $path }). +runner.io.write_stdout = Ninja-manifestet kunne ikke skrives til stdout. +runner.io.flush_stdout = Bufferen for stdout kunne ikke tømmes. + +# Manifestdiagnostikk. +manifest.parse = Innlesingen av manifestet mislyktes. +manifest.structure_error = Strukturfeil i manifestet ved { $name }: { $details } +manifest.yaml.parse = YAML-feil på linje { $line }, kolonne { $column }: { $details } +manifest.yaml.label = ugyldig YAML +manifest.yaml.hint.tabs = YAML tillater ikke tabulatorer; bruk mellomrom til innrykk. +manifest.yaml.hint.list_item = YAML-listeelementer må begynne med «-» og ha riktig innrykk. +manifest.yaml.hint.expected_colon = Dette ser ut som en oppføring i en tilordning; det mangler et «:» etter nøkkelen. +manifest.yaml.hint.mapping_values = YAML-tilordninger krever en verdi etter «:» (eller en blokk med innrykk). +manifest.yaml.hint.invalid_token = YAML-symbolet er ugyldig eller uventet. +manifest.yaml.hint.escape = Escape omvendte skråstreker, eller fjern ugyldige escape-sekvenser. +manifest.env.missing = Den påkrevde miljøvariabelen «{ $name }» er ikke satt. +manifest.env.invalid_utf8 = Miljøvariabelen «{ $name }» inneholder ugyldig UTF-8. +manifest.vars.not_object = `vars` i manifestet må være en tilordning eller et objekt. +manifest.read_failed = Manifestet i { $path } kunne ikke leses. +manifest.resolve_workspace_root = Roten til arbeidsområdet kunne ikke bestemmes. +manifest.workspace_non_utf8 = Rotstien til arbeidsområdet «{ $path }» er ikke gyldig UTF-8. +manifest.path_non_utf8 = Stien til manifestet «{ $manifest }» er ikke gyldig UTF-8: { $path }. +manifest.path_missing_name = Manifeststien «{ $path }» mangler filnavn. +manifest.open_workspace_failed = Arbeidsområdet { $workspace } kunne ikke åpnes for manifestet { $manifest }. +manifest.foreach.not_iterable = Uttrykket `foreach` kan ikke itereres over. +manifest.foreach.serialise_item = Elementet i `foreach` kunne ikke serialiseres. +manifest.when.empty = Uttrykket `when` kan ikke være tomt. +manifest.when.eval_error = Uttrykket `when` «{ $expr }» kunne ikke evalueres. +manifest.when.template_error = Malen `when` «{ $expr }» kunne ikke gjengis. +manifest.target.vars_not_object = `vars` for målet må være et objekt, men ga { $value }. +manifest.vars.entry_not_object = En `vars`-oppføring i manifestet må være et objekt. +manifest.field_not_string = Feltet «{ $field }» må være en streng. +manifest.expression.parse_error = Uttrykket { $name } kunne ikke leses inn. +manifest.expression.eval_error = Uttrykket { $name } kunne ikke evalueres. + +# Diagnostikk for manifestmakroer. +manifest.macro.signature_missing_identifier = Makrosignaturen mangler en identifikator. +manifest.macro.signature_missing_params = Makrosignaturen mangler parametere. +manifest.macro.compile_failed = Makroen { $name } kunne ikke kompileres. +manifest.macro.sequence_invalid = Makroer må defineres som en tilordning fra navn til maler. +manifest.macro.register_failed = Makroene i manifestet kunne ikke registreres. +manifest.macro.not_initialised = Makromiljøet er ikke klargjort. +manifest.macro.caller_invalid = Kalleren til makroen må være en streng. +manifest.macro.template_load_failed = Makromalen kunne ikke lastes inn. +manifest.macro.init_failed = Makromiljøet kunne ikke klargjøres. +manifest.macro.missing = Makroen { $name } mangler. + +# Glob-feil i manifestet. +manifest.glob.unmatched_brace = Ugyldig glob-mønster «{ $pattern }»: «{ $character }» uten motpart på posisjon { $position }. +manifest.glob.invalid_pattern = Ugyldig glob-mønster «{ $pattern }»: { $detail }. +manifest.glob.unknown_pattern_error = ukjent mønsterfeil. +manifest.glob.io_failed = Glob mislyktes for «{ $pattern }»: { $detail }. +manifest.glob.unknown_io_error = ukjent I/U-feil. + +# Feil i den interne representasjonen. +ir.rule_not_found = Regelen «{ $rule }» som målet «{ $target }» viser til, ble ikke funnet. +ir.multiple_rules = Målet «{ $target }» må vise til nøyaktig én regel, men ga { $rules }. +ir.empty_rule = Målet «{ $target }» må vise til en regel. +ir.duplicate_outputs = Det ble funnet dupliserte utdata: { $outputs }. +ir.circular_dependency = Det ble funnet en sirkulær avhengighet: { $cycle }. +ir.action_serialisation = Handlingen kunne ikke serialiseres: { $details }. +ir.invalid_command = Ugyldig interpolasjon i kommandoen: { $snippet }. + +# Feil ved generering av Ninja. +ninja_gen.missing_action = Handlingen «{ $id }» som en byggekant viser til, mangler. +ninja_gen.format = Utdataene fra Ninja-manifestet kunne ikke formateres. + +# Validering av vertsmønstre. +host_pattern.empty = Vertsmønsteret kan ikke være tomt. +host_pattern.contains_scheme = Vertsmønsteret «{ $pattern }» kan ikke inneholde et URL-skjema. +host_pattern.contains_slash = Vertsmønsteret «{ $pattern }» kan ikke inneholde «/». +host_pattern.missing_suffix = Vertsmønsteret «{ $pattern }» må ha et suffiks etter «*.». +host_pattern.empty_label = Vertsmønsteret «{ $pattern }» inneholder en tom etikett. +host_pattern.invalid_chars = Vertsmønsteret «{ $pattern }» inneholder ugyldige tegn. +host_pattern.invalid_label_edge = Etiketter i vertsmønsteret «{ $pattern }» kan ikke begynne eller slutte med «-». +host_pattern.label_too_long = Vertsmønsteret «{ $pattern }» inneholder en etikett på over 63 tegn. +host_pattern.too_long = Vertsmønsteret «{ $pattern }» overskrider grensen på 255 tegn. + +# Nettverksregler. +network_policy.scheme.empty = Skjemaet kan ikke være tomt. +network_policy.scheme.invalid = Skjemaet «{ $scheme }» inneholder ugyldige tegn. +network_policy.allowlist.empty = Listen over tillatte verter kan ikke være tom. +network_policy.scheme.not_allowed = Skjemaet «{ $scheme }» er ikke tillatt. +network_policy.missing_host = URL-adressen mangler vert. +network_policy.host.blocked = Verten «{ $host }» er blokkert av reglene. +network_policy.host.not_allowlisted = Verten «{ $host }» står ikke på listen over tillatte. + +# Konfigurasjon av standardbiblioteket. +stdlib.config.default_fetch_cache_invalid = Standardstien til fetch-hurtiglageret må være relativ. +stdlib.config.default_which_cache_invalid = Standardkapasiteten for which-hurtiglageret må være positiv. +stdlib.config.workspace_root_absolute = Rotstien til arbeidsområdet må være absolutt. +stdlib.config.fetch_response_limit_positive = Svargrensen for fetch må være positiv. +stdlib.config.command_output_limit_positive = Grensen for fanget kommandoutdata må være positiv. +stdlib.config.command_stream_limit_positive = Strømgrensen for kommandoer må være positiv. +stdlib.config.which_cache_capacity_positive = Kapasiteten for which-hurtiglageret må være positiv. +stdlib.config.skip_dir_empty = Oppføringer over katalogene som hoppes over, kan ikke være tomme. +stdlib.config.skip_dir_navigation = Oppføringer over katalogene som hoppes over, kan ikke inneholde «..». +stdlib.config.skip_dir_separator = Oppføringer over katalogene som hoppes over, kan ikke inneholde stiskilletegn. +stdlib.config.fetch_cache_empty = Stien til fetch-hurtiglageret kan ikke være tom. +stdlib.config.fetch_cache_not_relative = Stien til fetch-hurtiglageret må være relativ, men ga { $path }. +stdlib.config.fetch_cache_escapes = Stien til fetch-hurtiglageret kan ikke gå utenfor arbeidsområdet: { $path }. +stdlib.config.open_workspace_root = Gjeldende katalog kunne ikke åpnes som rot for stdlib-arbeidsområdet. +stdlib.config.resolve_cwd = Gjeldende katalog kunne ikke bestemmes som rot for stdlib-arbeidsområdet. +stdlib.config.cwd_non_utf8 = Gjeldende katalog inneholder deler som ikke er UTF-8: { $path }. + +# Diagnostikk for fetch-hjelperen. +stdlib.fetch.url_invalid = Ugyldig URL-adresse «{ $url }»: { $details }. +stdlib.fetch.disallowed = URL-adressen «{ $url }» er ikke tillatt: { $details }. +stdlib.fetch.failed = «{ $url }» kunne ikke hentes: { $details }. +stdlib.fetch.cache_read_failed = Oppføringen «{ $name }» i hurtiglageret kunne ikke leses: { $details }. +stdlib.fetch.cache_open_failed = Oppføringen «{ $name }» i hurtiglageret kunne ikke åpnes: { $details }. +stdlib.fetch.response_read_failed = Svaret fra «{ $url }» kunne ikke leses: { $details }. +stdlib.fetch.response_buffer_overflow = Bufferoverflyt under lesing av «{ $url }». +stdlib.fetch.cache_write_failed = Hurtiglageret for «{ $url }» kunne ikke skrives: { $details }. +stdlib.fetch.response_limit_exceeded = Svaret fra «{ $url }» oversteg grensen på { $limit } byte. +stdlib.fetch.cache_limit_exceeded = Det hurtiglagrede svaret «{ $name }» oversteg grensen på { $limit } byte. +stdlib.fetch.io_failed = { $action } mislyktes for { $path }: { $details }. +stdlib.fetch.action.sync_cache = synkronisering av fetch-hurtiglageret +stdlib.fetch.action.create_cache_dir = oppretting av katalogen for fetch-hurtiglageret +stdlib.fetch.action.open_cache_dir = åpning av katalogen for fetch-hurtiglageret +stdlib.fetch.action.stat_cache = oppslag på oppføringen i fetch-hurtiglageret +stdlib.fetch.action.open_cache_entry = åpning av oppføringen i fetch-hurtiglageret + +# Diagnostikk for kommandohjelperen. +stdlib.command.location = kommandoen «{ $command }» i malen «{ $template }» +stdlib.command.spawn_failed = { $location } kunne ikke startes: { $details }. +stdlib.command.io_failed = { $location } mislyktes: { $details }. +stdlib.command.closed_input_early = Inndataene ble lukket før skrivingen til kommandoen var ferdig. +stdlib.command.broken_pipe = Brutt datakanal under kjøring av { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } ble avbrutt av et signal. +stdlib.command.exited_with_status = { $location } avsluttet med status { $status }. +stdlib.command.output_limit_exceeded = { $location } oversteg { $mode }-grensen på { $limit } byte for { $stream }. +stdlib.command.timeout = { $location } overskred tidsgrensen på { $seconds } sekunder. +stdlib.command.exit_status_suffix = (avslutningsstatus { $status }) +stdlib.command.signal_suffix = (avbrutt av et signal) +stdlib.command.shell.empty = Skallkommandoen kan ikke være tom. +stdlib.command.grep.empty_pattern = Mønsteret til grep kan ikke være tomt. +stdlib.command.grep.flags_not_string = Flagg til grep må være strenger. +stdlib.command.quote.invalid = { $arg } kunne ikke settes i anførselstegn: { $details }. +stdlib.command.quote.line_break = Argumenter med vognretur eller linjeskift kan ikke settes trygt i anførselstegn. +stdlib.command.input_undefined = Inndataverdien er udefinert. +stdlib.command.tempfile.root_required = Roten til arbeidsområdet kreves for å opprette midlertidige kommandofiler. +stdlib.command.tempfile.create_failed = Den midlertidige kommandofilen kunne ikke opprettes: { $details }. +stdlib.command.options.invalid_utf8 = Nøkkelen til et kommandovalg må være gyldig UTF-8. +stdlib.command.option.mode_not_string = Utdatamodusen må være en streng. +stdlib.command.options.invalid_type = Kommandovalg må være et objekt. +stdlib.command.output.mode_unsupported = Utdatamodusen «{ $mode }» støttes ikke. +stdlib.command.output.mode.capture = fangst +stdlib.command.output.mode.streaming = strømming +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Diagnostikk for stihjelperen. +stdlib.path.io.failed = { $action } mislyktes for { $path } ({ $label }). +stdlib.path.io.failed_with_detail = { $action } mislyktes for { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = { $action } mislyktes for { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = ikke funnet +stdlib.path.io.permission_denied = tilgang nektet +stdlib.path.io.already_exists = finnes allerede +stdlib.path.io.invalid_input = ugyldige inndata +stdlib.path.io.invalid_data = ugyldige data +stdlib.path.io.timed_out = tidsgrensen løp ut +stdlib.path.io.interrupted = avbrutt +stdlib.path.io.would_block = ville blokkere +stdlib.path.io.write_zero = ingen byte skrevet +stdlib.path.io.unexpected_eof = uventet filslutt +stdlib.path.io.broken_pipe = brutt datakanal +stdlib.path.io.connection_refused = tilkoblingen ble avvist +stdlib.path.io.connection_reset = tilkoblingen ble nullstilt +stdlib.path.io.connection_aborted = tilkoblingen ble avbrutt +stdlib.path.io.not_connected = ikke tilkoblet +stdlib.path.io.addr_in_use = adressen er i bruk +stdlib.path.io.addr_not_available = adressen er ikke tilgjengelig +stdlib.path.io.out_of_memory = tomt for minne +stdlib.path.io.unsupported = støttes ikke +stdlib.path.io.file_too_large = filen er for stor +stdlib.path.io.resource_busy = ressursen er opptatt +stdlib.path.io.executable_busy = programfilen er opptatt +stdlib.path.io.deadlock = vranglås +stdlib.path.io.crosses_devices = krysser enheter +stdlib.path.io.too_many_links = for mange lenker +stdlib.path.io.invalid_filename = ugyldig filnavn +stdlib.path.io.arg_list_too_long = argumentlisten er for lang +stdlib.path.io.stale_handle = utdatert filhåndtak i nettverket +stdlib.path.io.storage_full = lageret er fullt +stdlib.path.io.not_seekable = kan ikke søkes i +stdlib.path.io.network_down = nettverket er nede +stdlib.path.io.network_unreachable = nettverket kan ikke nås +stdlib.path.io.host_unreachable = verten kan ikke nås +stdlib.path.io.other = I/U-feil +stdlib.path.action.canonicalize = kanonisering +stdlib.path.action.open_directory = åpning av katalog +stdlib.path.action.stat = oppslag +stdlib.path.action.read = lesing +stdlib.path.action.open_file = åpning av fil +stdlib.path.with_suffix.empty_separator = with_suffix krever et skilletegn som ikke er tomt. +stdlib.path.relative_to.mismatch = { $path } er ikke relativ til { $root }. +stdlib.path.expanduser.unsupported = Brukerspesifikk utvidelse av ~ støttes ikke. +stdlib.path.expanduser.no_home = ~ kan ikke utvides: ingen miljøvariabler for hjemmekatalogen er satt. +stdlib.path.contents.unsupported_encoding = Tegnkodingen «{ $encoding }» støttes ikke. +stdlib.path.hash.unsupported_algorithm = Hash-algoritmen «{ $algorithm }» støttes ikke. +stdlib.path.hash.unsupported_algorithm_legacy = Hash-algoritmen «{ $algorithm }» støttes ikke (slå på funksjonen «{ $feature }»). + +# Diagnostikk for samlingshjelpere. +stdlib.collections.flatten.expected_sequence = flatten ventet elementer fra en sekvens, men fant { $kind }. +stdlib.collections.group_by.empty_attribute = group_by krever et attributt som ikke er tomt. +stdlib.collections.group_by.unresolved = group_by kunne ikke slå opp «{ $attr }» på et element av typen { $kind }. + +# Diagnostikk for tidshjelpere. +stdlib.time.offset.invalid = Forskyvningen for now «{ $offset }» er ugyldig: ventet «+HH:MM[:SS]» eller «Z». +stdlib.time.timedelta.overflow = Overflyt i timedelta ved tillegg av { $component }. +stdlib.time.label.weeks = uker +stdlib.time.label.days = dager +stdlib.time.label.hours = timer +stdlib.time.label.minutes = minutter +stdlib.time.label.seconds = sekunder +stdlib.time.label.milliseconds = millisekunder +stdlib.time.label.microseconds = mikrosekunder +stdlib.time.label.nanoseconds = nanosekunder + +# Diagnostikk for which-hjelperen. +stdlib.which.not_found = [netsuke::jinja::which::not_found] kommandoen «{ $command }» ble ikke funnet etter gjennomgang av { $count } PATH-oppføringer. Utdrag: { $preview } +stdlib.which.not_found.hint.cwd_auto = Tomme deler av PATH ignoreres; bruk cwd_mode="auto" for å ta med arbeidskatalogen. +stdlib.which.not_found.hint.cwd_always = Sett cwd_mode="always" for å ta med gjeldende katalog. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] kommandoen «{ $command }» i «{ $path }» mangler eller kan ikke kjøres. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = PATH-oppføring nr. { $index } inneholder tegn som ikke er UTF-8; Netsuke krever UTF-8-stier. +stdlib.which.command.empty = which krever en streng som ikke er tom. +stdlib.which.cwd_mode.invalid = cwd_mode må være «auto», «always» eller «never», men ga «{ $mode }». +stdlib.which.cwd.resolve_failed = Gjeldende katalog kunne ikke bestemmes: { $details }. +stdlib.which.cwd.non_utf8 = Gjeldende katalog inneholder deler som ikke er UTF-8. +stdlib.which.canonicalize_failed = «{ $path }» kunne ikke kanoniseres: { $details }. +stdlib.which.is_executable = Det kunne ikke avgjøres om «{ $path }» kan kjøres: { $details }. +stdlib.which.canonicalize_non_utf8 = Den kanoniske stien inneholder deler som ikke er UTF-8. +stdlib.which.workspace_non_utf8 = Stien til arbeidsområdet inneholder deler som ikke er UTF-8 under oppslag av kommandoen «{ $command }»: { $path }. +stdlib.which.walkdir_error = Feil under gjennomgang av arbeidsområdet ved oppslag av kommandoen: { $details }. + +# Registrering av standardbiblioteket. +stdlib.register.open_dir = Gjeldende katalog kunne ikke åpnes for registrering av stdlib. +stdlib.register.resolve_dir = Gjeldende katalog kunne ikke bestemmes for registrering av stdlib. +stdlib.register.dir_non_utf8 = Gjeldende katalog inneholder deler som ikke er UTF-8: { $path }. + +# Statusrapportering for tilgjengelig utdatamodus. +status.state.pending = venter +status.state.running = pågår +status.state.done = ferdig +status.state.failed = mislyktes +status.stage.label = Trinn { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Oppgave { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Leser manifestfilen +status.stage.initial_yaml_parsing = Leser inn YAML-dokumentet +status.stage.template_expansion = Utvider maldirektiver +status.stage.final_rendering = Deserialiserer og gjengir verdiene i manifestet +status.stage.ir_generation_validation = Bygger og validerer avhengighetsgrafen +status.stage.ninja_synthesis = Lager Ninja-byggeplanen +status.stage.ninja_synthesis_execute = Lager Ninja-planen og kjører { $tool } +status.stage.graph_rendering = Gjengir grafartefaktet +status.stage.graph_rendering_with_tool = Gjengir { $tool } +status.complete = { $tool } fullført. +status.timing.summary_header = Tidsoppsummering per trinn: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Samlet tid for kjeden: { $duration } +status.tool.build = Bygging +status.tool.clean = Opprydding +status.tool.graph = Graf +status.tool.graph_html = Graf (HTML) +status.tool.generate = Generering + +# Tekster for HTML-gjengivelsen av grafen. +graph.html.title = Netsuke-byggegraf +graph.html.heading = Netsuke-byggegraf +graph.html.description = Byggegraf gjengitt av Netsuke +graph.html.outline.summary = Mål og avhengigheter (tekstoversikt) +graph.html.outline.no_inputs = Ingen inndata +graph.html.noscript.notice = JavaScript er slått av. Tekstoversikten over er hele grafen; DOT-kilden følger under. + +# Semantiske prefikser for tilgjengelig utdata. +semantic.prefix.error = Feil: +semantic.prefix.warning = Advarsel: +semantic.prefix.success = Vellykket: +semantic.prefix.info = Info: +semantic.prefix.timing = Tid: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Eksempler på flertallsformer for oversettere. +# Bokmål bruker CLDR-kategoriene `one` og `other`, som kildespråket. +example.files_processed = { $count -> + [one] Behandlet { $count } fil. + *[other] Behandlet { $count } filer. +} + +example.errors_found = { $count -> + [0] Ingen feil funnet. + [one] { $count } feil funnet. + *[other] { $count } feil funnet. +} diff --git a/locales/nl/messages.ftl b/locales/nl/messages.ftl new file mode 100644 index 000000000..c313a2fe2 --- /dev/null +++ b/locales/nl/messages.ftl @@ -0,0 +1,398 @@ +# Lokalisatiebronnen voor de opdrachtregel van Netsuke. + +cli.about = Netsuke compileert YAML- en Jinja-manifesten tot Ninja-bouwplannen. +cli.long_about = Netsuke zet YAML- en Jinja-manifesten om in reproduceerbare Ninja-grafen en voert Ninja uit met veilige standaardwaarden. +cli.usage = { $usage } + +# Helptekst voor algemene opties. +cli.flag.file.help = Pad naar het te gebruiken Netsuke-manifestbestand. +cli.flag.directory.help = Uitvoeren alsof er in deze map is gestart. +cli.flag.config.help = Pad naar een configuratiebestand; slaat het automatisch zoeken over. +cli.flag.jobs.help = Stel het aantal parallelle bouwtaken in. +cli.flag.verbose.help = Schakel uitgebreide diagnostische logging en tijdsoverzichten bij afronding in. +cli.flag.locale.help = Taalmarkering voor de teksten op de opdrachtregel (bijvoorbeeld: en-US, nl). +cli.flag.fetch_allow_scheme.help = Extra URL-schema's die de fetch-helper mag gebruiken. +cli.flag.fetch_allow_host.help = Hostnamen die zijn toegestaan wanneer standaardweigering aanstaat. +cli.flag.fetch_block_host.help = Hostnamen die altijd worden geblokkeerd, ook als ze elders zijn toegestaan. +cli.flag.fetch_default_deny.help = Weiger standaard alle hosts; sta alleen de opgegeven lijst toe. +cli.flag.json.help = Geef machineleesbare JSON-uitvoer. +cli.flag.no_input.help = Lees nooit interactieve invoer. +cli.flag.color.help = Beleid voor gekleurde uitvoer (auto, always, never). +cli.flag.emoji.help = Beleid voor emoji (auto, always, never). +cli.flag.progress.help = Beleid voor het tonen van voortgang (auto, always, never). +cli.flag.accessibility.help = Beleid voor toegankelijke uitvoer (auto, on, off). +cli.flag.default_targets.help = Standaarddoelen voor de bouw wanneer er geen zijn opgegeven. + +# Beschrijvingen van subopdrachten. +cli.subcommand.build.about = Bouw de doelen die in het manifest zijn gedefinieerd (standaard). +cli.subcommand.build.long_about = Bouw de gevraagde doelen; zijn er geen opgegeven, gebruik dan de standaarddoelen uit het manifest. +cli.subcommand.clean.about = Verwijder bouwartefacten via Ninja. +cli.subcommand.clean.long_about = Genereer een tijdelijk Ninja-bestand en voer daarna `ninja -t clean` uit. +cli.subcommand.graph.about = Geef de afhankelijkheidsgraaf van de bouw. De standaardindeling is DOT. +cli.subcommand.graph.long_about = Zet het ingelezen Netsuke-manifest om in een canonieke bouwgraaf en schrijf die weg als Graphviz DOT, of met `--html` als zelfstandige HTML-pagina. Gebruik `--output ` om naar een bestand te schrijven; `-` schrijft naar stdout. +cli.subcommand.generate.about = Genereer het Ninja-manifest zonder Ninja uit te voeren. +cli.subcommand.generate.long_about = Schrijf het gegenereerde Ninja-manifest naar stdout of naar een bestand dat met `--output` is gekozen. + +# Helptekst voor opties van de subopdracht build. +cli.subcommand.build.flag.targets.help = Te bouwen doelen (gebruikt de standaarddoelen uit het manifest als dit ontbreekt). + +# Helptekst voor opties van de subopdracht graph. +cli.subcommand.graph.flag.html.help = Geef de graaf weer als zelfstandige HTML-pagina in plaats van als DOT. +cli.subcommand.graph.flag.output.help = Schrijf het graafartefact naar BESTAND; gebruik `-` voor stdout. + +# Helptekst voor opties van de subopdracht generate. +cli.subcommand.generate.flag.output.help = Schrijf het gegenereerde Ninja-manifest naar BESTAND in plaats van naar stdout. + +# Validatiefouten op de opdrachtregel. +cli.validation.jobs.invalid_number = { $value } is geen geldig getal. +cli.validation.jobs.out_of_range = Het aantal taken moet tussen { $min } en { $max } liggen. +cli.validation.scheme.empty = Het schema mag niet leeg zijn. +cli.validation.scheme.invalid_start = Het schema ‘{ $scheme }’ moet met een ASCII-letter beginnen. +cli.validation.scheme.invalid = Ongeldig schema ‘{ $scheme }’. +cli.validation.locale.empty = De taalmarkering mag niet leeg zijn. +cli.validation.locale.invalid = Ongeldige taalmarkering ‘{ $locale }’. +cli.validation.color.invalid = Ongeldig kleurbeleid ‘{ $value }’. Geldige opties: auto, always, never. +cli.validation.emoji.invalid = Ongeldig emojibeleid ‘{ $value }’. Geldige opties: auto, always, never. +cli.validation.progress.invalid = Ongeldig voortgangsbeleid ‘{ $value }’. Geldige opties: auto, always, never. +cli.validation.accessibility.invalid = Ongeldig toegankelijkheidsbeleid ‘{ $value }’. Geldige opties: auto, on, off. +cli.validation.config.expected_object = De waarden van de opdrachtregel moesten naar een object worden geserialiseerd, maar gaven { $value }. + +# Foutmeldingen van Clap. +clap-error-missing-argument = Verplicht argument ontbreekt: { $argument } +clap-error-missing-subcommand = Subopdracht ontbreekt. Beschikbare opties: { $valid_subcommands } +clap-error-unknown-argument = Onbekend argument: { $argument } +clap-error-invalid-value = Ongeldige waarde voor { $argument }: { $value } +clap-error-invalid-subcommand = Onbekende subopdracht: { $subcommand } +# Let op: value-validation is anders geformuleerd dan invalid-value om fouten +# van eigen validators (ErrorKind::ValueValidation) te onderscheiden van +# typeconflicten (ErrorKind::InvalidValue). +clap-error-value-validation = Validatie mislukt voor { $argument }: { $value } + +# Fouten en context van de uitvoering. +runner.manifest.not_found = Manifest ‘{ $manifest_name }’ niet gevonden in { $directory }. +runner.manifest.not_found.help = Controleer of het manifest bestaat of geef `--file` met het juiste pad op. +runner.manifest.path_missing_name = Het manifestpad ‘{ $path }’ heeft geen bestandsnaam. +runner.manifest.path_utf8 = Het manifestpad ‘{ $path }’ is geen geldige UTF-8. +runner.manifest.directory_utf8 = Het pad van de manifestmap ‘{ $path }’ is geen geldige UTF-8. +runner.manifest.directory_label = map `{ $directory }` +runner.manifest.current_directory_label = de huidige map +runner.context.network_policy = Het netwerkbeleid kon niet worden opgebouwd. +runner.context.load_manifest = Het manifest in { $path } kon niet worden geladen. +runner.context.serialise_manifest = Het manifest kon niet worden geserialiseerd. +runner.context.build_graph = De graaf kon niet uit het manifest worden opgebouwd. +runner.context.generate_ninja = Het Ninja-manifest kon niet worden gegenereerd. +runner.context.render_graph = Het graafartefact kon niet worden weergegeven. + +runner.io.create_temp_file = Het tijdelijke Ninja-bestand kon niet worden aangemaakt. +runner.io.write_temp_ninja = Het tijdelijke Ninja-bestand kon niet worden geschreven. +runner.io.flush_temp_ninja = De buffer van het tijdelijke Ninja-bestand kon niet worden geleegd. +runner.io.sync_temp_ninja = Het tijdelijke Ninja-bestand kon niet worden gesynchroniseerd. +runner.io.create_parent_dir = De bovenliggende map { $path } kon niet worden aangemaakt. +runner.io.create_ninja_file = Het Ninja-bestand in { $path } kon niet worden aangemaakt. +runner.io.write_ninja_file = Het Ninja-bestand in { $path } kon niet worden geschreven. +runner.io.flush_ninja_file = De buffer van het Ninja-bestand in { $path } kon niet worden geleegd. +runner.io.sync_ninja_file = Het Ninja-bestand in { $path } kon niet worden gesynchroniseerd. +runner.io.open_ambient_dir = De omliggende map kon niet worden geopend. +runner.io.no_existing_ancestor = Er bestaat geen bovenliggende map voor { $path }. +runner.io.derive_relative_path = Het relatieve Ninja-pad kon niet worden afgeleid. +runner.io.non_utf8_path = Paden die geen UTF-8 zijn, worden niet ondersteund (pad: { $path }). +runner.io.write_stdout = Het Ninja-manifest kon niet naar stdout worden geschreven. +runner.io.flush_stdout = De buffer van stdout kon niet worden geleegd. + +# Manifestdiagnostiek. +manifest.parse = Het inlezen van het manifest is mislukt. +manifest.structure_error = Structuurfout in het manifest bij { $name }: { $details } +manifest.yaml.parse = YAML-fout op regel { $line }, kolom { $column }: { $details } +manifest.yaml.label = ongeldige YAML +manifest.yaml.hint.tabs = YAML staat geen tabs toe; gebruik spaties om in te springen. +manifest.yaml.hint.list_item = YAML-lijstitems moeten met ‘-’ beginnen en juist zijn ingesprongen. +manifest.yaml.hint.expected_colon = Dit lijkt een item in een toewijzing; na de sleutel ontbreekt een ‘:’. +manifest.yaml.hint.mapping_values = YAML-toewijzingen vereisen een waarde na ‘:’ (of een ingesprongen blok). +manifest.yaml.hint.invalid_token = Het YAML-token is ongeldig of onverwacht. +manifest.yaml.hint.escape = Escape de backslashes of verwijder ongeldige escapereeksen. +manifest.env.missing = De vereiste omgevingsvariabele ‘{ $name }’ is niet ingesteld. +manifest.env.invalid_utf8 = De omgevingsvariabele ‘{ $name }’ bevat ongeldige UTF-8. +manifest.vars.not_object = De `vars` van het manifest moet een toewijzing of object zijn. +manifest.read_failed = Het manifest in { $path } kon niet worden gelezen. +manifest.resolve_workspace_root = De hoofdmap van de werkruimte kon niet worden bepaald. +manifest.workspace_non_utf8 = Het hoofdpad van de werkruimte ‘{ $path }’ is geen geldige UTF-8. +manifest.path_non_utf8 = Het pad van manifest ‘{ $manifest }’ is geen geldige UTF-8: { $path }. +manifest.path_missing_name = Het manifestpad ‘{ $path }’ heeft geen bestandsnaam. +manifest.open_workspace_failed = De werkruimte { $workspace } kon niet worden geopend voor manifest { $manifest }. +manifest.foreach.not_iterable = De expressie `foreach` is niet doorloopbaar. +manifest.foreach.serialise_item = Het item van `foreach` kon niet worden geserialiseerd. +manifest.when.empty = De expressie `when` mag niet leeg zijn. +manifest.when.eval_error = De expressie `when` ‘{ $expr }’ kon niet worden geëvalueerd. +manifest.when.template_error = De sjabloon `when` ‘{ $expr }’ kon niet worden weergegeven. +manifest.target.vars_not_object = De `vars` van het doel moet een object zijn, maar gaf { $value }. +manifest.vars.entry_not_object = Een `vars`-item van het manifest moet een object zijn. +manifest.field_not_string = Het veld ‘{ $field }’ moet een tekenreeks zijn. +manifest.expression.parse_error = De expressie { $name } kon niet worden ingelezen. +manifest.expression.eval_error = De expressie { $name } kon niet worden geëvalueerd. + +# Diagnostiek voor manifestmacro's. +manifest.macro.signature_missing_identifier = In de macrodefinitie ontbreekt een naam. +manifest.macro.signature_missing_params = In de macrodefinitie ontbreken parameters. +manifest.macro.compile_failed = De macro { $name } kon niet worden gecompileerd. +manifest.macro.sequence_invalid = Macro's moeten worden gedefinieerd als een toewijzing van namen aan sjablonen. +manifest.macro.register_failed = De macro's van het manifest konden niet worden geregistreerd. +manifest.macro.not_initialised = De macro-omgeving is niet geïnitialiseerd. +manifest.macro.caller_invalid = De aanroeper van de macro moet een tekenreeks zijn. +manifest.macro.template_load_failed = De macrosjabloon kon niet worden geladen. +manifest.macro.init_failed = De macro-omgeving kon niet worden geïnitialiseerd. +manifest.macro.missing = De macro { $name } ontbreekt. + +# Glob-fouten in het manifest. +manifest.glob.unmatched_brace = Ongeldig glob-patroon ‘{ $pattern }’: ‘{ $character }’ zonder tegenhanger op positie { $position }. +manifest.glob.invalid_pattern = Ongeldig glob-patroon ‘{ $pattern }’: { $detail }. +manifest.glob.unknown_pattern_error = onbekende patroonfout. +manifest.glob.io_failed = Glob is mislukt voor ‘{ $pattern }’: { $detail }. +manifest.glob.unknown_io_error = onbekende I/O-fout. + +# Fouten in de tussenrepresentatie. +ir.rule_not_found = De regel ‘{ $rule }’ waarnaar doel ‘{ $target }’ verwijst, is niet gevonden. +ir.multiple_rules = Doel ‘{ $target }’ moet naar precies één regel verwijzen, maar gaf { $rules }. +ir.empty_rule = Doel ‘{ $target }’ moet naar een regel verwijzen. +ir.duplicate_outputs = Dubbele uitvoer aangetroffen: { $outputs }. +ir.circular_dependency = Circulaire afhankelijkheid aangetroffen: { $cycle }. +ir.action_serialisation = De actie kon niet worden geserialiseerd: { $details }. +ir.invalid_command = Ongeldige interpolatie in de opdracht: { $snippet }. + +# Fouten bij het genereren van Ninja. +ninja_gen.missing_action = De actie ‘{ $id }’ waarnaar een bouwtak verwijst, ontbreekt. +ninja_gen.format = De uitvoer van het Ninja-manifest kon niet worden opgemaakt. + +# Validatie van hostpatronen. +host_pattern.empty = Het hostpatroon mag niet leeg zijn. +host_pattern.contains_scheme = Het hostpatroon ‘{ $pattern }’ mag geen URL-schema bevatten. +host_pattern.contains_slash = Het hostpatroon ‘{ $pattern }’ mag geen ‘/’ bevatten. +host_pattern.missing_suffix = Het hostpatroon ‘{ $pattern }’ moet een achtervoegsel na ‘*.’ bevatten. +host_pattern.empty_label = Het hostpatroon ‘{ $pattern }’ bevat een leeg label. +host_pattern.invalid_chars = Het hostpatroon ‘{ $pattern }’ bevat ongeldige tekens. +host_pattern.invalid_label_edge = Labels in het hostpatroon ‘{ $pattern }’ mogen niet met ‘-’ beginnen of eindigen. +host_pattern.label_too_long = Het hostpatroon ‘{ $pattern }’ bevat een label van meer dan 63 tekens. +host_pattern.too_long = Het hostpatroon ‘{ $pattern }’ overschrijdt de limiet van 255 tekens. + +# Netwerkbeleid. +network_policy.scheme.empty = Het schema mag niet leeg zijn. +network_policy.scheme.invalid = Het schema ‘{ $scheme }’ bevat ongeldige tekens. +network_policy.allowlist.empty = De lijst met toegestane hosts mag niet leeg zijn. +network_policy.scheme.not_allowed = Het schema ‘{ $scheme }’ is niet toegestaan. +network_policy.missing_host = In de URL ontbreekt een host. +network_policy.host.blocked = Host ‘{ $host }’ wordt door het beleid geblokkeerd. +network_policy.host.not_allowlisted = Host ‘{ $host }’ staat niet op de lijst met toegestane hosts. + +# Configuratie van de standaardbibliotheek. +stdlib.config.default_fetch_cache_invalid = Het standaardpad van de fetch-cache moet relatief zijn. +stdlib.config.default_which_cache_invalid = De standaardcapaciteit van de which-cache moet positief zijn. +stdlib.config.workspace_root_absolute = Het hoofdpad van de werkruimte moet absoluut zijn. +stdlib.config.fetch_response_limit_positive = De antwoordlimiet van fetch moet positief zijn. +stdlib.config.command_output_limit_positive = De limiet voor vastgelegde opdrachtuitvoer moet positief zijn. +stdlib.config.command_stream_limit_positive = De streamlimiet voor opdrachten moet positief zijn. +stdlib.config.which_cache_capacity_positive = De capaciteit van de which-cache moet positief zijn. +stdlib.config.skip_dir_empty = Items voor over te slaan mappen mogen niet leeg zijn. +stdlib.config.skip_dir_navigation = Items voor over te slaan mappen mogen geen ‘..’ bevatten. +stdlib.config.skip_dir_separator = Items voor over te slaan mappen mogen geen padscheidingstekens bevatten. +stdlib.config.fetch_cache_empty = Het pad van de fetch-cache mag niet leeg zijn. +stdlib.config.fetch_cache_not_relative = Het pad van de fetch-cache moet relatief zijn, maar gaf { $path }. +stdlib.config.fetch_cache_escapes = Het pad van de fetch-cache mag de werkruimte niet verlaten: { $path }. +stdlib.config.open_workspace_root = De huidige map kon niet worden geopend als hoofdmap van de stdlib-werkruimte. +stdlib.config.resolve_cwd = De huidige map kon niet worden bepaald als hoofdmap van de stdlib-werkruimte. +stdlib.config.cwd_non_utf8 = De huidige map bevat delen die geen UTF-8 zijn: { $path }. + +# Diagnostiek van de fetch-helper. +stdlib.fetch.url_invalid = Ongeldige URL ‘{ $url }’: { $details }. +stdlib.fetch.disallowed = De URL ‘{ $url }’ is niet toegestaan: { $details }. +stdlib.fetch.failed = ‘{ $url }’ kon niet worden opgehaald: { $details }. +stdlib.fetch.cache_read_failed = Het cache-item ‘{ $name }’ kon niet worden gelezen: { $details }. +stdlib.fetch.cache_open_failed = Het cache-item ‘{ $name }’ kon niet worden geopend: { $details }. +stdlib.fetch.response_read_failed = Het antwoord van ‘{ $url }’ kon niet worden gelezen: { $details }. +stdlib.fetch.response_buffer_overflow = Bufferoverloop tijdens het lezen van ‘{ $url }’. +stdlib.fetch.cache_write_failed = De cache voor ‘{ $url }’ kon niet worden geschreven: { $details }. +stdlib.fetch.response_limit_exceeded = Het antwoord van ‘{ $url }’ overschreed de limiet van { $limit } bytes. +stdlib.fetch.cache_limit_exceeded = Het gecachete antwoord ‘{ $name }’ overschreed de limiet van { $limit } bytes. +stdlib.fetch.io_failed = { $action } is mislukt voor { $path }: { $details }. +stdlib.fetch.action.sync_cache = synchroniseren van de fetch-cache +stdlib.fetch.action.create_cache_dir = aanmaken van de fetch-cachemap +stdlib.fetch.action.open_cache_dir = openen van de fetch-cachemap +stdlib.fetch.action.stat_cache = opvragen van het item in de fetch-cache +stdlib.fetch.action.open_cache_entry = openen van het item in de fetch-cache + +# Diagnostiek van de opdrachthelper. +stdlib.command.location = opdracht ‘{ $command }’ in sjabloon ‘{ $template }’ +stdlib.command.spawn_failed = { $location } kon niet worden gestart: { $details }. +stdlib.command.io_failed = { $location } is mislukt: { $details }. +stdlib.command.closed_input_early = De invoer sloot voordat het schrijven naar de opdracht klaar was. +stdlib.command.broken_pipe = Verbroken pipe tijdens het uitvoeren van { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } is door een signaal beëindigd. +stdlib.command.exited_with_status = { $location } is geëindigd met status { $status }. +stdlib.command.output_limit_exceeded = { $location } overschreed de { $mode }-limiet van { $limit } bytes voor { $stream }. +stdlib.command.timeout = { $location } overschreed de tijdslimiet van { $seconds } seconden. +stdlib.command.exit_status_suffix = (afsluitstatus { $status }) +stdlib.command.signal_suffix = (door een signaal beëindigd) +stdlib.command.shell.empty = De shell-opdracht mag niet leeg zijn. +stdlib.command.grep.empty_pattern = Het grep-patroon mag niet leeg zijn. +stdlib.command.grep.flags_not_string = Vlaggen voor grep moeten tekenreeksen zijn. +stdlib.command.quote.invalid = { $arg } kon niet tussen aanhalingstekens worden gezet: { $details }. +stdlib.command.quote.line_break = Argumenten met een regelterugloop of regeleinde kunnen niet veilig tussen aanhalingstekens worden gezet. +stdlib.command.input_undefined = De invoerwaarde is niet gedefinieerd. +stdlib.command.tempfile.root_required = De hoofdmap van de werkruimte is vereist om tijdelijke opdrachtbestanden aan te maken. +stdlib.command.tempfile.create_failed = Het tijdelijke opdrachtbestand kon niet worden aangemaakt: { $details }. +stdlib.command.options.invalid_utf8 = De sleutel van een opdrachtoptie moet geldige UTF-8 zijn. +stdlib.command.option.mode_not_string = De uitvoermodus moet een tekenreeks zijn. +stdlib.command.options.invalid_type = Opdrachtopties moeten een object zijn. +stdlib.command.output.mode_unsupported = De uitvoermodus ‘{ $mode }’ wordt niet ondersteund. +stdlib.command.output.mode.capture = vastleggen +stdlib.command.output.mode.streaming = streamen +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Diagnostiek van de padhelper. +stdlib.path.io.failed = { $action } is mislukt voor { $path } ({ $label }). +stdlib.path.io.failed_with_detail = { $action } is mislukt voor { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = { $action } is mislukt voor { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = niet gevonden +stdlib.path.io.permission_denied = toegang geweigerd +stdlib.path.io.already_exists = bestaat al +stdlib.path.io.invalid_input = ongeldige invoer +stdlib.path.io.invalid_data = ongeldige gegevens +stdlib.path.io.timed_out = tijdslimiet verstreken +stdlib.path.io.interrupted = onderbroken +stdlib.path.io.would_block = zou blokkeren +stdlib.path.io.write_zero = nul bytes geschreven +stdlib.path.io.unexpected_eof = onverwacht einde van bestand +stdlib.path.io.broken_pipe = verbroken pipe +stdlib.path.io.connection_refused = verbinding geweigerd +stdlib.path.io.connection_reset = verbinding opnieuw ingesteld +stdlib.path.io.connection_aborted = verbinding afgebroken +stdlib.path.io.not_connected = niet verbonden +stdlib.path.io.addr_in_use = adres al in gebruik +stdlib.path.io.addr_not_available = adres niet beschikbaar +stdlib.path.io.out_of_memory = geen geheugen meer +stdlib.path.io.unsupported = niet ondersteund +stdlib.path.io.file_too_large = bestand te groot +stdlib.path.io.resource_busy = bron bezet +stdlib.path.io.executable_busy = uitvoerbaar bestand bezet +stdlib.path.io.deadlock = impasse +stdlib.path.io.crosses_devices = overschrijdt apparaten +stdlib.path.io.too_many_links = te veel koppelingen +stdlib.path.io.invalid_filename = ongeldige bestandsnaam +stdlib.path.io.arg_list_too_long = argumentenlijst te lang +stdlib.path.io.stale_handle = verouderde netwerkbestandsverwijzing +stdlib.path.io.storage_full = opslag vol +stdlib.path.io.not_seekable = niet doorzoekbaar +stdlib.path.io.network_down = netwerk ligt plat +stdlib.path.io.network_unreachable = netwerk onbereikbaar +stdlib.path.io.host_unreachable = host onbereikbaar +stdlib.path.io.other = I/O-fout +stdlib.path.action.canonicalize = canoniseren +stdlib.path.action.open_directory = openen van de map +stdlib.path.action.stat = opvragen +stdlib.path.action.read = lezen +stdlib.path.action.open_file = openen van het bestand +stdlib.path.with_suffix.empty_separator = with_suffix vereist een scheidingsteken dat niet leeg is. +stdlib.path.relative_to.mismatch = { $path } is niet relatief ten opzichte van { $root }. +stdlib.path.expanduser.unsupported = Gebruikerspecifieke uitbreiding van ~ wordt niet ondersteund. +stdlib.path.expanduser.no_home = ~ kan niet worden uitgebreid: er zijn geen omgevingsvariabelen voor de thuismap ingesteld. +stdlib.path.contents.unsupported_encoding = De tekencodering ‘{ $encoding }’ wordt niet ondersteund. +stdlib.path.hash.unsupported_algorithm = Het hash-algoritme ‘{ $algorithm }’ wordt niet ondersteund. +stdlib.path.hash.unsupported_algorithm_legacy = Het hash-algoritme ‘{ $algorithm }’ wordt niet ondersteund (schakel functie ‘{ $feature }’ in). + +# Diagnostiek van de verzamelinghelpers. +stdlib.collections.flatten.expected_sequence = flatten verwachtte items uit een reeks, maar vond { $kind }. +stdlib.collections.group_by.empty_attribute = group_by vereist een attribuut dat niet leeg is. +stdlib.collections.group_by.unresolved = group_by kon ‘{ $attr }’ niet vinden op een item van het type { $kind }. + +# Diagnostiek van de tijdhelpers. +stdlib.time.offset.invalid = De verschuiving voor now ‘{ $offset }’ is ongeldig: verwacht werd ‘+HH:MM[:SS]’ of ‘Z’. +stdlib.time.timedelta.overflow = Overloop in timedelta bij het optellen van { $component }. +stdlib.time.label.weeks = weken +stdlib.time.label.days = dagen +stdlib.time.label.hours = uren +stdlib.time.label.minutes = minuten +stdlib.time.label.seconds = seconden +stdlib.time.label.milliseconds = milliseconden +stdlib.time.label.microseconds = microseconden +stdlib.time.label.nanoseconds = nanoseconden + +# Diagnostiek van de which-helper. +stdlib.which.not_found = [netsuke::jinja::which::not_found] opdracht ‘{ $command }’ niet gevonden na het doorlopen van { $count } PATH-items. Voorbeeld: { $preview } +stdlib.which.not_found.hint.cwd_auto = Lege delen van PATH worden genegeerd; gebruik cwd_mode="auto" om de werkmap mee te nemen. +stdlib.which.not_found.hint.cwd_always = Stel cwd_mode="always" in om de huidige map mee te nemen. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] de opdracht ‘{ $command }’ in ‘{ $path }’ ontbreekt of is niet uitvoerbaar. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = PATH-item nr. { $index } bevat tekens die geen UTF-8 zijn; Netsuke vereist UTF-8-paden. +stdlib.which.command.empty = which vereist een tekenreeks die niet leeg is. +stdlib.which.cwd_mode.invalid = cwd_mode moet ‘auto’, ‘always’ of ‘never’ zijn, maar gaf ‘{ $mode }’. +stdlib.which.cwd.resolve_failed = De huidige map kon niet worden bepaald: { $details }. +stdlib.which.cwd.non_utf8 = De huidige map bevat delen die geen UTF-8 zijn. +stdlib.which.canonicalize_failed = ‘{ $path }’ kon niet worden gecanoniseerd: { $details }. +stdlib.which.is_executable = Er kon niet worden vastgesteld of ‘{ $path }’ uitvoerbaar is: { $details }. +stdlib.which.canonicalize_non_utf8 = Het canonieke pad bevat delen die geen UTF-8 zijn. +stdlib.which.workspace_non_utf8 = Het pad van de werkruimte bevat delen die geen UTF-8 zijn bij het opzoeken van opdracht ‘{ $command }’: { $path }. +stdlib.which.walkdir_error = Fout bij het doorlopen van de werkruimte tijdens het opzoeken van de opdracht: { $details }. + +# Registratie van de standaardbibliotheek. +stdlib.register.open_dir = De huidige map kon niet worden geopend voor de registratie van stdlib. +stdlib.register.resolve_dir = De huidige map kon niet worden bepaald voor de registratie van stdlib. +stdlib.register.dir_non_utf8 = De huidige map bevat delen die geen UTF-8 zijn: { $path }. + +# Statusrapportage voor de toegankelijke uitvoermodus. +status.state.pending = in de wachtrij +status.state.running = bezig +status.state.done = klaar +status.state.failed = mislukt +status.stage.label = Stap { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Taak { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Manifestbestand lezen +status.stage.initial_yaml_parsing = YAML-document inlezen +status.stage.template_expansion = Sjabloondirectieven uitbreiden +status.stage.final_rendering = Manifestwaarden deserialiseren en weergeven +status.stage.ir_generation_validation = Afhankelijkheidsgraaf opbouwen en controleren +status.stage.ninja_synthesis = Ninja-bouwplan samenstellen +status.stage.ninja_synthesis_execute = Ninja-plan samenstellen en { $tool } uitvoeren +status.stage.graph_rendering = Graafartefact weergeven +status.stage.graph_rendering_with_tool = { $tool } weergeven +status.complete = { $tool } voltooid. +status.timing.summary_header = Tijdsoverzicht per stap: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Totale tijd van de keten: { $duration } +status.tool.build = Bouw +status.tool.clean = Opruimen +status.tool.graph = Graaf +status.tool.graph_html = Graaf (HTML) +status.tool.generate = Genereren + +# Teksten van de HTML-weergave van de graaf. +graph.html.title = Netsuke-bouwgraaf +graph.html.heading = Netsuke-bouwgraaf +graph.html.description = Bouwgraaf weergegeven door Netsuke +graph.html.outline.summary = Doelen en afhankelijkheden (tekstoverzicht) +graph.html.outline.no_inputs = Geen invoer +graph.html.noscript.notice = JavaScript staat uit. Het tekstoverzicht hierboven is de volledige graaf; de DOT-broncode volgt hieronder. + +# Semantische voorvoegsels voor toegankelijke uitvoer. +semantic.prefix.error = Fout: +semantic.prefix.warning = Waarschuwing: +semantic.prefix.success = Gelukt: +semantic.prefix.info = Info: +semantic.prefix.timing = Tijd: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Voorbeelden van meervoudsvormen voor vertalers. +# Het Nederlands gebruikt de CLDR-categorieën `one` en `other`, net als de +# brontaal. +example.files_processed = { $count -> + [one] { $count } bestand verwerkt. + *[other] { $count } bestanden verwerkt. +} + +example.errors_found = { $count -> + [0] Geen fouten gevonden. + [one] { $count } fout gevonden. + *[other] { $count } fouten gevonden. +} diff --git a/locales/pl/messages.ftl b/locales/pl/messages.ftl new file mode 100644 index 000000000..6393bca3f --- /dev/null +++ b/locales/pl/messages.ftl @@ -0,0 +1,403 @@ +# Zasoby lokalizacyjne wiersza poleceń Netsuke. + +cli.about = Netsuke kompiluje manifesty YAML + Jinja do planów budowania Ninja. +cli.long_about = Netsuke przekształca manifesty YAML + Jinja w powtarzalne grafy Ninja i uruchamia Ninję z bezpiecznymi ustawieniami domyślnymi. +cli.usage = { $usage } + +# Tekst pomocy opcji globalnych. +cli.flag.file.help = Ścieżka do pliku manifestu Netsuke, który ma zostać użyty. +cli.flag.directory.help = Uruchom tak, jakby start nastąpił w tym katalogu. +cli.flag.config.help = Ścieżka do pliku konfiguracyjnego, z pominięciem automatycznego wyszukiwania. +cli.flag.jobs.help = Ustaw liczbę równoległych zadań budowania. +cli.flag.verbose.help = Włącz szczegółowe rejestrowanie diagnostyczne i podsumowania czasów po zakończeniu. +cli.flag.locale.help = Znacznik języka tekstów wiersza poleceń (na przykład: en-US, pl). +cli.flag.fetch_allow_scheme.help = Dodatkowe schematy URL dozwolone dla pomocnika fetch. +cli.flag.fetch_allow_host.help = Nazwy hostów dozwolone, gdy włączona jest domyślna odmowa. +cli.flag.fetch_block_host.help = Nazwy hostów zawsze blokowane, nawet jeśli są dozwolone gdzie indziej. +cli.flag.fetch_default_deny.help = Odmawiaj domyślnie wszystkim hostom; zezwalaj tylko na zadeklarowaną listę. +cli.flag.json.help = Wypisuj dane wyjściowe JSON czytelne dla maszyn. +cli.flag.no_input.help = Nigdy nie czytaj danych wprowadzanych interaktywnie. +cli.flag.color.help = Zasada kolorowania wyjścia (auto, always, never). +cli.flag.emoji.help = Zasada użycia emoji (auto, always, never). +cli.flag.progress.help = Zasada wyświetlania postępu (auto, always, never). +cli.flag.accessibility.help = Zasada wyjścia dostępnego (auto, on, off). +cli.flag.default_targets.help = Domyślne cele budowania, gdy nie podano żadnego. + +# Opisy podpoleceń. +cli.subcommand.build.about = Zbuduj cele zdefiniowane w manifeście (domyślne). +cli.subcommand.build.long_about = Zbuduj żądane cele; jeśli żadnego nie podano, użyj celów domyślnych z manifestu. +cli.subcommand.clean.about = Usuń artefakty budowania za pomocą Ninji. +cli.subcommand.clean.long_about = Wygeneruj tymczasowy plik Ninja, a następnie uruchom `ninja -t clean`. +cli.subcommand.graph.about = Wypisz graf zależności budowania. Domyślnym formatem jest DOT. +cli.subcommand.graph.long_about = Przekształć wczytany manifest Netsuke w kanoniczny graf budowania i zapisz go jako Graphviz DOT albo — z opcją `--html` — jako samodzielną stronę HTML. Użyj `--output `, aby zapisać do pliku; `-` zapisuje na standardowe wyjście. +cli.subcommand.generate.about = Wygeneruj manifest Ninja bez uruchamiania Ninji. +cli.subcommand.generate.long_about = Zapisz wygenerowany manifest Ninja na standardowe wyjście albo do pliku wybranego opcją `--output`. + +# Tekst pomocy opcji podpolecenia build. +cli.subcommand.build.flag.targets.help = Cele do zbudowania (w razie pominięcia używa celów domyślnych z manifestu). + +# Tekst pomocy opcji podpolecenia graph. +cli.subcommand.graph.flag.html.help = Wyrenderuj graf jako samodzielną stronę HTML zamiast formatu DOT. +cli.subcommand.graph.flag.output.help = Zapisz artefakt grafu do PLIKU; użyj `-` dla standardowego wyjścia. + +# Tekst pomocy opcji podpolecenia generate. +cli.subcommand.generate.flag.output.help = Zapisz wygenerowany manifest Ninja do PLIKU zamiast na standardowe wyjście. + +# Błędy walidacji wiersza poleceń. +cli.validation.jobs.invalid_number = { $value } nie jest prawidłową liczbą. +cli.validation.jobs.out_of_range = Liczba zadań musi mieścić się w przedziale od { $min } do { $max }. +cli.validation.scheme.empty = Schemat nie może być pusty. +cli.validation.scheme.invalid_start = Schemat „{ $scheme }” musi zaczynać się literą ASCII. +cli.validation.scheme.invalid = Nieprawidłowy schemat „{ $scheme }”. +cli.validation.locale.empty = Znacznik języka nie może być pusty. +cli.validation.locale.invalid = Nieprawidłowy znacznik języka „{ $locale }”. +cli.validation.color.invalid = Nieprawidłowa zasada kolorowania „{ $value }”. Prawidłowe opcje: auto, always, never. +cli.validation.emoji.invalid = Nieprawidłowa zasada emoji „{ $value }”. Prawidłowe opcje: auto, always, never. +cli.validation.progress.invalid = Nieprawidłowa zasada postępu „{ $value }”. Prawidłowe opcje: auto, always, never. +cli.validation.accessibility.invalid = Nieprawidłowa zasada dostępności „{ $value }”. Prawidłowe opcje: auto, on, off. +cli.validation.config.expected_object = Wartości wiersza poleceń miały zostać zserializowane do obiektu, otrzymano { $value }. + +# Komunikaty błędów z Clap. +clap-error-missing-argument = Brak wymaganego argumentu: { $argument } +clap-error-missing-subcommand = Brak podpolecenia. Dostępne opcje: { $valid_subcommands } +clap-error-unknown-argument = Nieznany argument: { $argument } +clap-error-invalid-value = Nieprawidłowa wartość argumentu { $argument }: { $value } +clap-error-invalid-subcommand = Nieznane podpolecenie: { $subcommand } +# Uwaga: value-validation sformułowano inaczej niż invalid-value, aby odróżnić +# błędy własnych walidatorów (ErrorKind::ValueValidation) od niezgodności typów +# (ErrorKind::InvalidValue). +clap-error-value-validation = Walidacja nie powiodła się dla { $argument }: { $value } + +# Błędy i kontekst wykonania. +runner.manifest.not_found = Nie znaleziono manifestu „{ $manifest_name }” w katalogu { $directory }. +runner.manifest.not_found.help = Upewnij się, że manifest istnieje, albo podaj `--file` z właściwą ścieżką. +runner.manifest.path_missing_name = Ścieżka manifestu „{ $path }” nie zawiera nazwy pliku. +runner.manifest.path_utf8 = Ścieżka manifestu „{ $path }” nie jest prawidłowym UTF-8. +runner.manifest.directory_utf8 = Ścieżka katalogu manifestu „{ $path }” nie jest prawidłowym UTF-8. +runner.manifest.directory_label = katalog `{ $directory }` +runner.manifest.current_directory_label = bieżący katalog +runner.context.network_policy = Nie udało się zbudować zasad sieciowych. +runner.context.load_manifest = Nie udało się wczytać manifestu z { $path }. +runner.context.serialise_manifest = Nie udało się zserializować manifestu. +runner.context.build_graph = Nie udało się zbudować grafu na podstawie manifestu. +runner.context.generate_ninja = Nie udało się wygenerować manifestu Ninja. +runner.context.render_graph = Nie udało się wyrenderować artefaktu grafu. + +runner.io.create_temp_file = Nie udało się utworzyć tymczasowego pliku Ninja. +runner.io.write_temp_ninja = Nie udało się zapisać tymczasowego pliku Ninja. +runner.io.flush_temp_ninja = Nie udało się opróżnić bufora tymczasowego pliku Ninja. +runner.io.sync_temp_ninja = Nie udało się zsynchronizować tymczasowego pliku Ninja. +runner.io.create_parent_dir = Nie udało się utworzyć katalogu nadrzędnego { $path }. +runner.io.create_ninja_file = Nie udało się utworzyć pliku Ninja w { $path }. +runner.io.write_ninja_file = Nie udało się zapisać pliku Ninja w { $path }. +runner.io.flush_ninja_file = Nie udało się opróżnić bufora pliku Ninja w { $path }. +runner.io.sync_ninja_file = Nie udało się zsynchronizować pliku Ninja w { $path }. +runner.io.open_ambient_dir = Nie udało się otworzyć katalogu otoczenia. +runner.io.no_existing_ancestor = Dla { $path } nie istnieje żaden katalog nadrzędny. +runner.io.derive_relative_path = Nie udało się wyznaczyć względnej ścieżki Ninja. +runner.io.non_utf8_path = Ścieżki inne niż UTF-8 nie są obsługiwane (ścieżka: { $path }). +runner.io.write_stdout = Nie udało się zapisać manifestu Ninja na standardowe wyjście. +runner.io.flush_stdout = Nie udało się opróżnić bufora standardowego wyjścia. + +# Diagnostyka manifestu. +manifest.parse = Analiza manifestu nie powiodła się. +manifest.structure_error = Błąd struktury manifestu w { $name }: { $details } +manifest.yaml.parse = Błąd analizy YAML w wierszu { $line }, kolumnie { $column }: { $details } +manifest.yaml.label = nieprawidłowy YAML +manifest.yaml.hint.tabs = YAML nie dopuszcza tabulatorów; do wcięć używaj spacji. +manifest.yaml.hint.list_item = Elementy listy YAML muszą zaczynać się od „-” i mieć prawidłowe wcięcie. +manifest.yaml.hint.expected_colon = To wygląda na wpis odwzorowania; po kluczu brakuje „:”. +manifest.yaml.hint.mapping_values = Odwzorowania YAML wymagają wartości po „:” (albo zagnieżdżonego bloku). +manifest.yaml.hint.invalid_token = Token YAML jest nieprawidłowy lub nieoczekiwany. +manifest.yaml.hint.escape = Poprzedź ukośniki odwrotne znakiem ucieczki albo usuń nieprawidłowe sekwencje. +manifest.env.missing = Wymagana zmienna środowiskowa „{ $name }” nie jest ustawiona. +manifest.env.invalid_utf8 = Zmienna środowiskowa „{ $name }” zawiera nieprawidłowy UTF-8. +manifest.vars.not_object = Pole `vars` manifestu musi być odwzorowaniem lub obiektem. +manifest.read_failed = Nie udało się odczytać manifestu z { $path }. +manifest.resolve_workspace_root = Nie udało się ustalić katalogu głównego obszaru roboczego. +manifest.workspace_non_utf8 = Ścieżka główna obszaru roboczego „{ $path }” nie jest prawidłowym UTF-8. +manifest.path_non_utf8 = Ścieżka manifestu „{ $manifest }” nie jest prawidłowym UTF-8: { $path }. +manifest.path_missing_name = Ścieżka manifestu „{ $path }” nie zawiera nazwy pliku. +manifest.open_workspace_failed = Nie udało się otworzyć obszaru roboczego { $workspace } dla manifestu { $manifest }. +manifest.foreach.not_iterable = Wyrażenie `foreach` nie jest iterowalne. +manifest.foreach.serialise_item = Nie udało się zserializować elementu `foreach`. +manifest.when.empty = Wyrażenie `when` nie może być puste. +manifest.when.eval_error = Nie udało się obliczyć wyrażenia `when` „{ $expr }”. +manifest.when.template_error = Nie udało się wyrenderować szablonu `when` „{ $expr }”. +manifest.target.vars_not_object = Pole `vars` celu musi być obiektem, otrzymano { $value }. +manifest.vars.entry_not_object = Wpis `vars` manifestu musi być obiektem. +manifest.field_not_string = Pole „{ $field }” musi być łańcuchem znaków. +manifest.expression.parse_error = Nie udało się przeanalizować wyrażenia { $name }. +manifest.expression.eval_error = Nie udało się obliczyć wyrażenia { $name }. + +# Diagnostyka makr manifestu. +manifest.macro.signature_missing_identifier = W sygnaturze makra brakuje identyfikatora. +manifest.macro.signature_missing_params = W sygnaturze makra brakuje parametrów. +manifest.macro.compile_failed = Nie udało się skompilować makra { $name }. +manifest.macro.sequence_invalid = Makra muszą być zdefiniowane jako odwzorowanie nazw na szablony. +manifest.macro.register_failed = Nie udało się zarejestrować makr manifestu. +manifest.macro.not_initialised = Środowisko makr nie zostało zainicjowane. +manifest.macro.caller_invalid = Wywołujący makro musi być łańcuchem znaków. +manifest.macro.template_load_failed = Nie udało się wczytać szablonu makra. +manifest.macro.init_failed = Nie udało się zainicjować środowiska makr. +manifest.macro.missing = Brakuje makra { $name }. + +# Błędy wzorców glob w manifeście. +manifest.glob.unmatched_brace = Nieprawidłowy wzorzec glob „{ $pattern }”: „{ $character }” bez pary na pozycji { $position }. +manifest.glob.invalid_pattern = Nieprawidłowy wzorzec glob „{ $pattern }”: { $detail }. +manifest.glob.unknown_pattern_error = nieznany błąd wzorca. +manifest.glob.io_failed = Wzorzec glob „{ $pattern }” zawiódł: { $detail }. +manifest.glob.unknown_io_error = nieznany błąd wejścia/wyjścia. + +# Błędy reprezentacji pośredniej. +ir.rule_not_found = Nie znaleziono reguły „{ $rule }”, do której odwołuje się cel „{ $target }”. +ir.multiple_rules = Cel „{ $target }” musi odwoływać się do dokładnie jednej reguły, otrzymano { $rules }. +ir.empty_rule = Cel „{ $target }” musi odwoływać się do reguły. +ir.duplicate_outputs = Wykryto zduplikowane wyjścia: { $outputs }. +ir.circular_dependency = Wykryto zależność cykliczną: { $cycle }. +ir.action_serialisation = Nie udało się zserializować akcji: { $details }. +ir.invalid_command = Nieprawidłowa interpolacja w poleceniu: { $snippet }. + +# Błędy generowania plików Ninja. +ninja_gen.missing_action = Brakuje akcji „{ $id }”, do której odwołuje się krawędź budowania. +ninja_gen.format = Nie udało się sformatować wyjścia manifestu Ninja. + +# Walidacja wzorców hostów. +host_pattern.empty = Wzorzec hosta nie może być pusty. +host_pattern.contains_scheme = Wzorzec hosta „{ $pattern }” nie może zawierać schematu URL. +host_pattern.contains_slash = Wzorzec hosta „{ $pattern }” nie może zawierać znaku „/”. +host_pattern.missing_suffix = Wzorzec hosta „{ $pattern }” musi zawierać przyrostek po „*.”. +host_pattern.empty_label = Wzorzec hosta „{ $pattern }” zawiera pustą etykietę. +host_pattern.invalid_chars = Wzorzec hosta „{ $pattern }” zawiera nieprawidłowe znaki. +host_pattern.invalid_label_edge = Etykiety wzorca hosta „{ $pattern }” nie mogą zaczynać się ani kończyć znakiem „-”. +host_pattern.label_too_long = Wzorzec hosta „{ $pattern }” zawiera etykietę dłuższą niż 63 znaki. +host_pattern.too_long = Wzorzec hosta „{ $pattern }” przekracza limit 255 znaków. + +# Zasady sieciowe. +network_policy.scheme.empty = Schemat nie może być pusty. +network_policy.scheme.invalid = Schemat „{ $scheme }” zawiera nieprawidłowe znaki. +network_policy.allowlist.empty = Lista dozwolonych hostów nie może być pusta. +network_policy.scheme.not_allowed = Schemat „{ $scheme }” nie jest dozwolony. +network_policy.missing_host = W adresie URL brakuje hosta. +network_policy.host.blocked = Host „{ $host }” jest zablokowany przez zasady. +network_policy.host.not_allowlisted = Hosta „{ $host }” nie ma na liście dozwolonych. + +# Konfiguracja biblioteki standardowej. +stdlib.config.default_fetch_cache_invalid = Domyślna ścieżka pamięci podręcznej fetch musi być względna. +stdlib.config.default_which_cache_invalid = Domyślna pojemność pamięci podręcznej which musi być dodatnia. +stdlib.config.workspace_root_absolute = Ścieżka główna obszaru roboczego musi być bezwzględna. +stdlib.config.fetch_response_limit_positive = Limit odpowiedzi fetch musi być dodatni. +stdlib.config.command_output_limit_positive = Limit przechwytywanego wyjścia poleceń musi być dodatni. +stdlib.config.command_stream_limit_positive = Limit strumienia poleceń musi być dodatni. +stdlib.config.which_cache_capacity_positive = Pojemność pamięci podręcznej which musi być dodatnia. +stdlib.config.skip_dir_empty = Wpisy pomijanych katalogów nie mogą być puste. +stdlib.config.skip_dir_navigation = Wpisy pomijanych katalogów nie mogą zawierać „..”. +stdlib.config.skip_dir_separator = Wpisy pomijanych katalogów nie mogą zawierać separatorów ścieżki. +stdlib.config.fetch_cache_empty = Ścieżka pamięci podręcznej fetch nie może być pusta. +stdlib.config.fetch_cache_not_relative = Ścieżka pamięci podręcznej fetch musi być względna, otrzymano { $path }. +stdlib.config.fetch_cache_escapes = Ścieżka pamięci podręcznej fetch nie może wychodzić poza obszar roboczy: { $path }. +stdlib.config.open_workspace_root = Nie udało się otworzyć bieżącego katalogu jako katalogu głównego obszaru roboczego stdlib. +stdlib.config.resolve_cwd = Nie udało się ustalić bieżącego katalogu jako katalogu głównego obszaru roboczego stdlib. +stdlib.config.cwd_non_utf8 = Bieżący katalog zawiera elementy inne niż UTF-8: { $path }. + +# Diagnostyka pomocnika fetch. +stdlib.fetch.url_invalid = Nieprawidłowy adres URL „{ $url }”: { $details }. +stdlib.fetch.disallowed = Adres URL „{ $url }” jest niedozwolony: { $details }. +stdlib.fetch.failed = Nie udało się pobrać „{ $url }”: { $details }. +stdlib.fetch.cache_read_failed = Nie udało się odczytać wpisu pamięci podręcznej „{ $name }”: { $details }. +stdlib.fetch.cache_open_failed = Nie udało się otworzyć wpisu pamięci podręcznej „{ $name }”: { $details }. +stdlib.fetch.response_read_failed = Nie udało się odczytać odpowiedzi z „{ $url }”: { $details }. +stdlib.fetch.response_buffer_overflow = Przepełnienie bufora podczas odczytu „{ $url }”. +stdlib.fetch.cache_write_failed = Nie udało się zapisać pamięci podręcznej dla „{ $url }”: { $details }. +stdlib.fetch.response_limit_exceeded = Odpowiedź z „{ $url }” przekroczyła limit { $limit } bajtów. +stdlib.fetch.cache_limit_exceeded = Zapisana w pamięci podręcznej odpowiedź „{ $name }” przekroczyła limit { $limit } bajtów. +stdlib.fetch.io_failed = Operacja „{ $action }” nie powiodła się dla { $path }: { $details }. +stdlib.fetch.action.sync_cache = synchronizacja pamięci podręcznej fetch +stdlib.fetch.action.create_cache_dir = utworzenie katalogu pamięci podręcznej fetch +stdlib.fetch.action.open_cache_dir = otwarcie katalogu pamięci podręcznej fetch +stdlib.fetch.action.stat_cache = odczyt informacji o wpisie pamięci podręcznej fetch +stdlib.fetch.action.open_cache_entry = otwarcie wpisu pamięci podręcznej fetch + +# Diagnostyka pomocnika poleceń. +stdlib.command.location = polecenie „{ $command }” w szablonie „{ $template }” +stdlib.command.spawn_failed = Nie udało się uruchomić { $location }: { $details }. +stdlib.command.io_failed = { $location } nie powiodło się: { $details }. +stdlib.command.closed_input_early = Wejście zamknięto przed zakończeniem zapisu do polecenia. +stdlib.command.broken_pipe = Przerwany potok podczas wykonywania { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } zostało przerwane sygnałem. +stdlib.command.exited_with_status = { $location } zakończyło się ze statusem { $status }. +stdlib.command.output_limit_exceeded = { $location } przekroczyło limit { $mode } wynoszący { $limit } bajtów dla { $stream }. +stdlib.command.timeout = { $location } przekroczyło limit czasu wynoszący { $seconds } s. +stdlib.command.exit_status_suffix = (status zakończenia { $status }) +stdlib.command.signal_suffix = (przerwane sygnałem) +stdlib.command.shell.empty = Polecenie powłoki nie może być puste. +stdlib.command.grep.empty_pattern = Wzorzec grep nie może być pusty. +stdlib.command.grep.flags_not_string = Flagi grep muszą być łańcuchami znaków. +stdlib.command.quote.invalid = Nie udało się ująć { $arg } w cudzysłów: { $details }. +stdlib.command.quote.line_break = Argumentów zawierających powrót karetki lub znak nowego wiersza nie da się bezpiecznie ująć w cudzysłów. +stdlib.command.input_undefined = Wartość wejściowa jest niezdefiniowana. +stdlib.command.tempfile.root_required = Do tworzenia plików tymczasowych poleceń wymagany jest katalog główny obszaru roboczego. +stdlib.command.tempfile.create_failed = Nie udało się utworzyć pliku tymczasowego polecenia: { $details }. +stdlib.command.options.invalid_utf8 = Klucz opcji polecenia musi być prawidłowym UTF-8. +stdlib.command.option.mode_not_string = Tryb wyjścia musi być łańcuchem znaków. +stdlib.command.options.invalid_type = Opcje polecenia muszą być obiektem. +stdlib.command.output.mode_unsupported = Nieobsługiwany tryb wyjścia „{ $mode }”. +stdlib.command.output.mode.capture = przechwytywanie +stdlib.command.output.mode.streaming = strumieniowanie +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Diagnostyka pomocnika ścieżek. +stdlib.path.io.failed = Operacja „{ $action }” nie powiodła się dla { $path } ({ $label }). +stdlib.path.io.failed_with_detail = Operacja „{ $action }” nie powiodła się dla { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = Operacja „{ $action }” nie powiodła się dla { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = nie znaleziono +stdlib.path.io.permission_denied = odmowa dostępu +stdlib.path.io.already_exists = już istnieje +stdlib.path.io.invalid_input = nieprawidłowe dane wejściowe +stdlib.path.io.invalid_data = nieprawidłowe dane +stdlib.path.io.timed_out = przekroczono limit czasu +stdlib.path.io.interrupted = przerwano +stdlib.path.io.would_block = spowodowałoby zablokowanie +stdlib.path.io.write_zero = zapisano zero bajtów +stdlib.path.io.unexpected_eof = nieoczekiwany koniec pliku +stdlib.path.io.broken_pipe = przerwany potok +stdlib.path.io.connection_refused = odmowa połączenia +stdlib.path.io.connection_reset = połączenie zresetowane +stdlib.path.io.connection_aborted = połączenie przerwane +stdlib.path.io.not_connected = brak połączenia +stdlib.path.io.addr_in_use = adres jest już używany +stdlib.path.io.addr_not_available = adres niedostępny +stdlib.path.io.out_of_memory = brak pamięci +stdlib.path.io.unsupported = nieobsługiwane +stdlib.path.io.file_too_large = plik zbyt duży +stdlib.path.io.resource_busy = zasób zajęty +stdlib.path.io.executable_busy = plik wykonywalny zajęty +stdlib.path.io.deadlock = zakleszczenie +stdlib.path.io.crosses_devices = przekracza granicę urządzeń +stdlib.path.io.too_many_links = zbyt wiele dowiązań +stdlib.path.io.invalid_filename = nieprawidłowa nazwa pliku +stdlib.path.io.arg_list_too_long = lista argumentów zbyt długa +stdlib.path.io.stale_handle = nieaktualny uchwyt pliku sieciowego +stdlib.path.io.storage_full = brak miejsca w pamięci masowej +stdlib.path.io.not_seekable = brak możliwości zmiany pozycji +stdlib.path.io.network_down = sieć niedziałająca +stdlib.path.io.network_unreachable = sieć nieosiągalna +stdlib.path.io.host_unreachable = host nieosiągalny +stdlib.path.io.other = błąd wejścia/wyjścia +stdlib.path.action.canonicalize = kanonizacja +stdlib.path.action.open_directory = otwarcie katalogu +stdlib.path.action.stat = odczyt informacji +stdlib.path.action.read = odczyt +stdlib.path.action.open_file = otwarcie pliku +stdlib.path.with_suffix.empty_separator = with_suffix wymaga niepustego separatora. +stdlib.path.relative_to.mismatch = Ścieżka { $path } nie jest względna względem { $root }. +stdlib.path.expanduser.unsupported = Rozwijanie ~ dla konkretnego użytkownika nie jest obsługiwane. +stdlib.path.expanduser.no_home = Nie można rozwinąć ~: nie ustawiono żadnej zmiennej środowiskowej katalogu domowego. +stdlib.path.contents.unsupported_encoding = Nieobsługiwane kodowanie „{ $encoding }”. +stdlib.path.hash.unsupported_algorithm = Nieobsługiwany algorytm skrótu „{ $algorithm }”. +stdlib.path.hash.unsupported_algorithm_legacy = Nieobsługiwany algorytm skrótu „{ $algorithm }” (włącz funkcję „{ $feature }”). + +# Diagnostyka pomocników kolekcji. +stdlib.collections.flatten.expected_sequence = flatten oczekiwał elementów sekwencji, ale napotkał { $kind }. +stdlib.collections.group_by.empty_attribute = group_by wymaga niepustego atrybutu. +stdlib.collections.group_by.unresolved = group_by nie zdołał odnaleźć „{ $attr }” w elemencie typu { $kind }. + +# Diagnostyka pomocników czasu. +stdlib.time.offset.invalid = Przesunięcie now „{ $offset }” jest nieprawidłowe: oczekiwano „+HH:MM[:SS]” albo „Z”. +stdlib.time.timedelta.overflow = Przepełnienie timedelta przy dodawaniu składnika { $component }. +stdlib.time.label.weeks = tygodnie +stdlib.time.label.days = dni +stdlib.time.label.hours = godziny +stdlib.time.label.minutes = minuty +stdlib.time.label.seconds = sekundy +stdlib.time.label.milliseconds = milisekundy +stdlib.time.label.microseconds = mikrosekundy +stdlib.time.label.nanoseconds = nanosekundy + +# Diagnostyka pomocnika which. +stdlib.which.not_found = [netsuke::jinja::which::not_found] nie znaleziono polecenia „{ $command }” po sprawdzeniu { $count } wpisów zmiennej PATH. Podgląd: { $preview } +stdlib.which.not_found.hint.cwd_auto = Puste segmenty zmiennej PATH są pomijane; użyj cwd_mode="auto", aby uwzględnić katalog roboczy. +stdlib.which.not_found.hint.cwd_always = Ustaw cwd_mode="always", aby uwzględnić bieżący katalog. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] polecenia „{ $command }” w „{ $path }” brakuje albo nie jest wykonywalne. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = Wpis nr { $index } zmiennej PATH zawiera znaki inne niż UTF-8; Netsuke wymaga ścieżek w UTF-8. +stdlib.which.command.empty = which wymaga niepustego łańcucha znaków. +stdlib.which.cwd_mode.invalid = cwd_mode musi mieć wartość „auto”, „always” albo „never”, otrzymano „{ $mode }”. +stdlib.which.cwd.resolve_failed = Nie udało się ustalić bieżącego katalogu: { $details }. +stdlib.which.cwd.non_utf8 = Bieżący katalog zawiera elementy inne niż UTF-8. +stdlib.which.canonicalize_failed = Nie udało się skanonizować „{ $path }”: { $details }. +stdlib.which.is_executable = Nie udało się sprawdzić, czy „{ $path }” jest wykonywalne: { $details }. +stdlib.which.canonicalize_non_utf8 = Ścieżka kanoniczna zawiera elementy inne niż UTF-8. +stdlib.which.workspace_non_utf8 = Ścieżka obszaru roboczego zawiera elementy inne niż UTF-8 podczas rozwiązywania polecenia „{ $command }”: { $path }. +stdlib.which.walkdir_error = Błąd przechodzenia obszaru roboczego podczas rozwiązywania polecenia: { $details }. + +# Rejestracja biblioteki standardowej. +stdlib.register.open_dir = Nie udało się otworzyć bieżącego katalogu na potrzeby rejestracji stdlib. +stdlib.register.resolve_dir = Nie udało się ustalić bieżącego katalogu na potrzeby rejestracji stdlib. +stdlib.register.dir_non_utf8 = Bieżący katalog zawiera elementy inne niż UTF-8: { $path }. + +# Raportowanie stanu w dostępnym trybie wyjścia. +status.state.pending = oczekuje +status.state.running = w toku +status.state.done = gotowe +status.state.failed = niepowodzenie +status.stage.label = Etap { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Zadanie { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Odczyt pliku manifestu +status.stage.initial_yaml_parsing = Analiza dokumentu YAML +status.stage.template_expansion = Rozwijanie dyrektyw szablonu +status.stage.final_rendering = Deserializacja i renderowanie wartości manifestu +status.stage.ir_generation_validation = Budowanie i sprawdzanie grafu zależności +status.stage.ninja_synthesis = Tworzenie planu budowania Ninja +status.stage.ninja_synthesis_execute = Tworzenie planu Ninja i uruchamianie { $tool } +status.stage.graph_rendering = Renderowanie artefaktu grafu +status.stage.graph_rendering_with_tool = Renderowanie { $tool } +status.complete = { $tool } zakończono. +status.timing.summary_header = Podsumowanie czasów etapów: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Łączny czas potoku: { $duration } +status.tool.build = Budowanie +status.tool.clean = Czyszczenie +status.tool.graph = Graf +status.tool.graph_html = Graf (HTML) +status.tool.generate = Generowanie + +# Teksty renderera HTML grafu. +graph.html.title = Graf budowania Netsuke +graph.html.heading = Graf budowania Netsuke +graph.html.description = Graf budowania wyrenderowany przez Netsuke +graph.html.outline.summary = Cele i zależności (zarys tekstowy) +graph.html.outline.no_inputs = Brak wejść +graph.html.noscript.notice = JavaScript jest wyłączony. Powyższy zarys tekstowy zawiera cały graf; poniżej znajduje się źródło DOT. + +# Przedrostki semantyczne dostępnego wyjścia. +semantic.prefix.error = Błąd: +semantic.prefix.warning = Ostrzeżenie: +semantic.prefix.success = Powodzenie: +semantic.prefix.info = Informacja: +semantic.prefix.timing = Czas: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Przykłady form liczby mnogiej dla tłumaczy. +# Polski korzysta z czterech kategorii CLDR: `one`, `few`, `many` i `other`. +# `few` obejmuje liczby kończące się na 2–4 (22–24, 32–34 itd.), ale nie +# 12–14; `many` obejmuje 12–14 oraz pozostałe liczby całkowite. +example.files_processed = { $count -> + [one] Przetworzono { $count } plik. + [few] Przetworzono { $count } pliki. + [many] Przetworzono { $count } plików. + *[other] Przetworzono { $count } pliku. +} + +example.errors_found = { $count -> + [0] Nie znaleziono błędów. + [one] Znaleziono { $count } błąd. + [few] Znaleziono { $count } błędy. + [many] Znaleziono { $count } błędów. + *[other] Znaleziono { $count } błędu. +} diff --git a/locales/pt-BR/messages.ftl b/locales/pt-BR/messages.ftl new file mode 100644 index 000000000..8895f790f --- /dev/null +++ b/locales/pt-BR/messages.ftl @@ -0,0 +1,399 @@ +# Recursos de localização da CLI do Netsuke (português do Brasil). + +cli.about = O Netsuke compila manifestos YAML + Jinja em planos de build do Ninja. +cli.long_about = O Netsuke transforma manifestos YAML + Jinja em grafos do Ninja reproduzíveis e executa o Ninja com padrões seguros. +cli.usage = { $usage } + +# Texto de ajuda das opções globais. +cli.flag.file.help = Caminho do arquivo de manifesto do Netsuke a ser usado. +cli.flag.directory.help = Executar como se tivesse sido iniciado neste diretório. +cli.flag.config.help = Caminho de um arquivo de configuração, ignorando a descoberta automática. +cli.flag.jobs.help = Define a quantidade de tarefas de build em paralelo. +cli.flag.verbose.help = Habilita logs de diagnóstico detalhados e resumos de tempo ao concluir. +cli.flag.locale.help = Tag de idioma para os textos da CLI (por exemplo: en-US, pt-BR). +cli.flag.fetch_allow_scheme.help = Esquemas de URL adicionais permitidos para o auxiliar fetch. +cli.flag.fetch_allow_host.help = Nomes de host permitidos quando a negação padrão está ativa. +cli.flag.fetch_block_host.help = Nomes de host sempre bloqueados, mesmo que permitidos em outro lugar. +cli.flag.fetch_default_deny.help = Negar todos os hosts por padrão; permitir apenas a lista declarada. +cli.flag.json.help = Emitir saída JSON legível por máquina. +cli.flag.no_input.help = Nunca ler entrada interativa. +cli.flag.color.help = Política de cor na saída (auto, always, never). +cli.flag.emoji.help = Política de emojis (auto, always, never). +cli.flag.progress.help = Política de exibição do progresso (auto, always, never). +cli.flag.accessibility.help = Política de saída acessível (auto, on, off). +cli.flag.default_targets.help = Alvos de build padrão quando nenhum é informado. + +# Descrições dos subcomandos. +cli.subcommand.build.about = Compilar os alvos definidos no manifesto (padrão). +cli.subcommand.build.long_about = Compilar os alvos solicitados; se nenhum for informado, usar os padrões do manifesto. +cli.subcommand.clean.about = Remover os artefatos de build por meio do Ninja. +cli.subcommand.clean.long_about = Gerar um arquivo Ninja temporário e depois executar `ninja -t clean`. +cli.subcommand.graph.about = Emitir o grafo de dependências do build. O formato padrão é DOT. +cli.subcommand.graph.long_about = Projetar o manifesto do Netsuke analisado em um grafo de build canônico e gravá-lo como Graphviz DOT ou como página HTML autocontida com `--html`. Use `--output ` para gravar em um arquivo; `-` grava na stdout. +cli.subcommand.generate.about = Gerar o manifesto do Ninja sem executar o Ninja. +cli.subcommand.generate.long_about = Gravar o manifesto do Ninja gerado na stdout ou no arquivo escolhido com `--output`. + +# Texto de ajuda das opções do subcomando build. +cli.subcommand.build.flag.targets.help = Alvos a compilar (se omitido, usa os padrões do manifesto). + +# Texto de ajuda das opções do subcomando graph. +cli.subcommand.graph.flag.html.help = Renderizar o grafo como página HTML autocontida em vez de DOT. +cli.subcommand.graph.flag.output.help = Gravar o artefato do grafo em ARQUIVO; use `-` para a stdout. + +# Texto de ajuda das opções do subcomando generate. +cli.subcommand.generate.flag.output.help = Gravar o manifesto do Ninja gerado em ARQUIVO em vez da stdout. + +# Erros de validação da CLI. +cli.validation.jobs.invalid_number = { $value } não é um número válido. +cli.validation.jobs.out_of_range = A quantidade de tarefas deve estar entre { $min } e { $max }. +cli.validation.scheme.empty = O esquema não pode estar vazio. +cli.validation.scheme.invalid_start = O esquema "{ $scheme }" deve começar com uma letra ASCII. +cli.validation.scheme.invalid = Esquema inválido "{ $scheme }". +cli.validation.locale.empty = A tag de idioma não pode estar vazia. +cli.validation.locale.invalid = Tag de idioma inválida "{ $locale }". +cli.validation.color.invalid = Política de cor inválida "{ $value }". Opções válidas: auto, always, never. +cli.validation.emoji.invalid = Política de emojis inválida "{ $value }". Opções válidas: auto, always, never. +cli.validation.progress.invalid = Política de progresso inválida "{ $value }". Opções válidas: auto, always, never. +cli.validation.accessibility.invalid = Política de acessibilidade inválida "{ $value }". Opções válidas: auto, on, off. +cli.validation.config.expected_object = Esperava-se que os valores da CLI fossem serializados como objeto, obteve-se { $value }. + +# Mensagens de erro do Clap. +clap-error-missing-argument = Falta um argumento obrigatório: { $argument } +clap-error-missing-subcommand = Falta o subcomando. Opções disponíveis: { $valid_subcommands } +clap-error-unknown-argument = Argumento desconhecido: { $argument } +clap-error-invalid-value = Valor inválido para { $argument }: { $value } +clap-error-invalid-subcommand = Subcomando desconhecido: { $subcommand } +# Observação: value-validation usa uma redação distinta de invalid-value para +# diferenciar falhas de validadores personalizados +# (ErrorKind::ValueValidation) de incompatibilidades de tipo +# (ErrorKind::InvalidValue). +clap-error-value-validation = A validação falhou para { $argument }: { $value } + +# Erros e contextos do executor. +runner.manifest.not_found = Manifesto "{ $manifest_name }" não encontrado em { $directory }. +runner.manifest.not_found.help = Verifique se o manifesto existe ou informe `--file` com o caminho correto. +runner.manifest.path_missing_name = O caminho do manifesto "{ $path }" não tem nome de arquivo. +runner.manifest.path_utf8 = O caminho do manifesto "{ $path }" não é UTF-8 válido. +runner.manifest.directory_utf8 = O caminho do diretório do manifesto "{ $path }" não é UTF-8 válido. +runner.manifest.directory_label = diretório `{ $directory }` +runner.manifest.current_directory_label = o diretório atual +runner.context.network_policy = Não foi possível construir a política de rede. +runner.context.load_manifest = Não foi possível carregar o manifesto em { $path }. +runner.context.serialise_manifest = Não foi possível serializar o manifesto. +runner.context.build_graph = Não foi possível construir o grafo a partir do manifesto. +runner.context.generate_ninja = Não foi possível gerar o manifesto do Ninja. +runner.context.render_graph = Não foi possível renderizar o artefato do grafo. + +runner.io.create_temp_file = Não foi possível criar o arquivo Ninja temporário. +runner.io.write_temp_ninja = Não foi possível gravar o arquivo Ninja temporário. +runner.io.flush_temp_ninja = Não foi possível esvaziar o buffer do arquivo Ninja temporário. +runner.io.sync_temp_ninja = Não foi possível sincronizar o arquivo Ninja temporário. +runner.io.create_parent_dir = Não foi possível criar o diretório pai { $path }. +runner.io.create_ninja_file = Não foi possível criar o arquivo Ninja em { $path }. +runner.io.write_ninja_file = Não foi possível gravar o arquivo Ninja em { $path }. +runner.io.flush_ninja_file = Não foi possível esvaziar o buffer do arquivo Ninja em { $path }. +runner.io.sync_ninja_file = Não foi possível sincronizar o arquivo Ninja em { $path }. +runner.io.open_ambient_dir = Não foi possível abrir o diretório do ambiente. +runner.io.no_existing_ancestor = Não existe diretório ancestral para { $path }. +runner.io.derive_relative_path = Não foi possível derivar o caminho relativo do Ninja. +runner.io.non_utf8_path = Não há suporte para caminhos que não sejam UTF-8 (caminho: { $path }). +runner.io.write_stdout = Não foi possível gravar o manifesto do Ninja na stdout. +runner.io.flush_stdout = Não foi possível esvaziar o buffer da stdout. + +# Diagnósticos do manifesto. +manifest.parse = A análise do manifesto falhou. +manifest.structure_error = Erro de estrutura do manifesto em { $name }: { $details } +manifest.yaml.parse = Erro de análise do YAML na linha { $line }, coluna { $column }: { $details } +manifest.yaml.label = YAML inválido +manifest.yaml.hint.tabs = O YAML não permite tabulações; use espaços na indentação. +manifest.yaml.hint.list_item = Itens de lista do YAML devem começar com "-" e estar corretamente indentados. +manifest.yaml.hint.expected_colon = Isto parece uma entrada de mapeamento; falta um ":" depois da chave. +manifest.yaml.hint.mapping_values = Mapeamentos do YAML exigem um valor depois de ":" (ou um bloco aninhado). +manifest.yaml.hint.invalid_token = O token do YAML é inválido ou inesperado. +manifest.yaml.hint.escape = Escape as barras invertidas ou remova as sequências de escape inválidas. +manifest.env.missing = A variável de ambiente obrigatória "{ $name }" não está definida. +manifest.env.invalid_utf8 = A variável de ambiente "{ $name }" contém UTF-8 inválido. +manifest.vars.not_object = `vars` do manifesto deve ser um mapa ou objeto. +manifest.read_failed = Não foi possível ler o manifesto em { $path }. +manifest.resolve_workspace_root = Não foi possível resolver a raiz do workspace. +manifest.workspace_non_utf8 = O caminho da raiz do workspace "{ $path }" não é UTF-8 válido. +manifest.path_non_utf8 = O caminho do manifesto "{ $manifest }" não é UTF-8 válido: { $path }. +manifest.path_missing_name = O caminho do manifesto "{ $path }" não tem nome de arquivo. +manifest.open_workspace_failed = Não foi possível abrir o workspace { $workspace } para o manifesto { $manifest }. +manifest.foreach.not_iterable = A expressão `foreach` não é iterável. +manifest.foreach.serialise_item = Não foi possível serializar o item de `foreach`. +manifest.when.empty = A expressão `when` não pode estar vazia. +manifest.when.eval_error = Não foi possível avaliar a expressão `when` "{ $expr }". +manifest.when.template_error = Não foi possível renderizar o template `when` "{ $expr }". +manifest.target.vars_not_object = `vars` do alvo deve ser um objeto, obteve-se { $value }. +manifest.vars.entry_not_object = Uma entrada `vars` do manifesto deve ser um objeto. +manifest.field_not_string = O campo "{ $field }" deve ser uma string. +manifest.expression.parse_error = Não foi possível analisar a expressão { $name }. +manifest.expression.eval_error = Não foi possível avaliar a expressão { $name }. + +# Diagnósticos das macros do manifesto. +manifest.macro.signature_missing_identifier = Falta um identificador na assinatura da macro. +manifest.macro.signature_missing_params = Faltam parâmetros na assinatura da macro. +manifest.macro.compile_failed = Não foi possível compilar a macro { $name }. +manifest.macro.sequence_invalid = As macros devem ser definidas como um mapeamento de nomes para templates. +manifest.macro.register_failed = Não foi possível registrar as macros do manifesto. +manifest.macro.not_initialised = O ambiente de macros não está inicializado. +manifest.macro.caller_invalid = O chamador da macro deve ser uma string. +manifest.macro.template_load_failed = Não foi possível carregar o template da macro. +manifest.macro.init_failed = Não foi possível inicializar o ambiente de macros. +manifest.macro.missing = A macro { $name } está ausente. + +# Erros de glob do manifesto. +manifest.glob.unmatched_brace = Padrão glob inválido "{ $pattern }": "{ $character }" sem correspondência na posição { $position }. +manifest.glob.invalid_pattern = Padrão glob inválido "{ $pattern }": { $detail }. +manifest.glob.unknown_pattern_error = erro de padrão desconhecido. +manifest.glob.io_failed = O glob falhou para "{ $pattern }": { $detail }. +manifest.glob.unknown_io_error = erro de E/S desconhecido. + +# Erros da representação intermediária. +ir.rule_not_found = A regra "{ $rule }" referenciada pelo alvo "{ $target }" não foi encontrada. +ir.multiple_rules = O alvo "{ $target }" deve referenciar uma única regra, obteve-se { $rules }. +ir.empty_rule = O alvo "{ $target }" deve referenciar uma regra. +ir.duplicate_outputs = Saídas duplicadas detectadas: { $outputs }. +ir.circular_dependency = Dependência circular detectada: { $cycle }. +ir.action_serialisation = Não foi possível serializar a ação: { $details }. +ir.invalid_command = Interpolação de comando inválida: { $snippet }. + +# Erros de geração do Ninja. +ninja_gen.missing_action = Falta a ação "{ $id }" referenciada por uma aresta de build. +ninja_gen.format = Não foi possível formatar a saída do manifesto do Ninja. + +# Validação de padrões de host. +host_pattern.empty = O padrão de host não pode estar vazio. +host_pattern.contains_scheme = O padrão de host "{ $pattern }" não pode incluir um esquema de URL. +host_pattern.contains_slash = O padrão de host "{ $pattern }" não pode incluir "/". +host_pattern.missing_suffix = O padrão de host "{ $pattern }" deve incluir um sufixo depois de "*.". +host_pattern.empty_label = O padrão de host "{ $pattern }" contém um rótulo vazio. +host_pattern.invalid_chars = O padrão de host "{ $pattern }" contém caracteres inválidos. +host_pattern.invalid_label_edge = Os rótulos do padrão de host "{ $pattern }" não podem começar nem terminar com "-". +host_pattern.label_too_long = O padrão de host "{ $pattern }" contém um rótulo com mais de 63 caracteres. +host_pattern.too_long = O padrão de host "{ $pattern }" excede o limite de 255 caracteres. + +# Política de rede. +network_policy.scheme.empty = O esquema não pode estar vazio. +network_policy.scheme.invalid = O esquema "{ $scheme }" contém caracteres inválidos. +network_policy.allowlist.empty = A lista de hosts permitidos não pode estar vazia. +network_policy.scheme.not_allowed = O esquema "{ $scheme }" não é permitido. +network_policy.missing_host = A URL não tem host. +network_policy.host.blocked = O host "{ $host }" está bloqueado pela política. +network_policy.host.not_allowlisted = O host "{ $host }" não está na lista de permitidos. + +# Configuração da biblioteca padrão. +stdlib.config.default_fetch_cache_invalid = O caminho padrão do cache do fetch deve ser relativo. +stdlib.config.default_which_cache_invalid = A capacidade padrão do cache do which deve ser positiva. +stdlib.config.workspace_root_absolute = O caminho da raiz do workspace deve ser absoluto. +stdlib.config.fetch_response_limit_positive = O limite de resposta do fetch deve ser positivo. +stdlib.config.command_output_limit_positive = O limite de captura da saída dos comandos deve ser positivo. +stdlib.config.command_stream_limit_positive = O limite de streaming dos comandos deve ser positivo. +stdlib.config.which_cache_capacity_positive = A capacidade do cache do which deve ser positiva. +stdlib.config.skip_dir_empty = As entradas de diretórios ignorados não podem estar vazias. +stdlib.config.skip_dir_navigation = As entradas de diretórios ignorados não podem conter "..". +stdlib.config.skip_dir_separator = As entradas de diretórios ignorados não podem conter separadores de caminho. +stdlib.config.fetch_cache_empty = O caminho do cache do fetch não pode estar vazio. +stdlib.config.fetch_cache_not_relative = O caminho do cache do fetch deve ser relativo, obteve-se { $path }. +stdlib.config.fetch_cache_escapes = O caminho do cache do fetch não pode sair do workspace: { $path }. +stdlib.config.open_workspace_root = Não foi possível abrir o diretório atual como raiz do workspace da stdlib. +stdlib.config.resolve_cwd = Não foi possível resolver o diretório atual como raiz do workspace da stdlib. +stdlib.config.cwd_non_utf8 = O diretório atual contém componentes que não são UTF-8: { $path }. + +# Diagnósticos do auxiliar fetch. +stdlib.fetch.url_invalid = URL inválida "{ $url }": { $details }. +stdlib.fetch.disallowed = A URL "{ $url }" não é permitida: { $details }. +stdlib.fetch.failed = Não foi possível baixar "{ $url }": { $details }. +stdlib.fetch.cache_read_failed = Não foi possível ler a entrada de cache "{ $name }": { $details }. +stdlib.fetch.cache_open_failed = Não foi possível abrir a entrada de cache "{ $name }": { $details }. +stdlib.fetch.response_read_failed = Não foi possível ler a resposta de "{ $url }": { $details }. +stdlib.fetch.response_buffer_overflow = Estouro do buffer ao ler "{ $url }". +stdlib.fetch.cache_write_failed = Não foi possível gravar o cache de "{ $url }": { $details }. +stdlib.fetch.response_limit_exceeded = A resposta de "{ $url }" excedeu o limite de { $limit } bytes. +stdlib.fetch.cache_limit_exceeded = A resposta em cache "{ $name }" excedeu o limite de { $limit } bytes. +stdlib.fetch.io_failed = { $action } falhou para { $path }: { $details }. +stdlib.fetch.action.sync_cache = sincronizar o cache do fetch +stdlib.fetch.action.create_cache_dir = criar o diretório de cache do fetch +stdlib.fetch.action.open_cache_dir = abrir o diretório de cache do fetch +stdlib.fetch.action.stat_cache = consultar a entrada de cache do fetch +stdlib.fetch.action.open_cache_entry = abrir a entrada de cache do fetch + +# Diagnósticos do auxiliar de comandos. +stdlib.command.location = comando "{ $command }" no template "{ $template }" +stdlib.command.spawn_failed = Não foi possível iniciar { $location }: { $details }. +stdlib.command.io_failed = { $location } falhou: { $details }. +stdlib.command.closed_input_early = A entrada foi fechada antes de concluir a gravação para o comando. +stdlib.command.broken_pipe = Pipe quebrado ao executar { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } foi encerrado por um sinal. +stdlib.command.exited_with_status = { $location } terminou com status { $status }. +stdlib.command.output_limit_exceeded = { $location } excedeu o limite de { $mode } de { $limit } bytes para { $stream }. +stdlib.command.timeout = { $location } excedeu o tempo limite de { $seconds } segundos. +stdlib.command.exit_status_suffix = (status de saída { $status }) +stdlib.command.signal_suffix = (encerrado por um sinal) +stdlib.command.shell.empty = O comando de shell não pode estar vazio. +stdlib.command.grep.empty_pattern = O padrão do grep não pode estar vazio. +stdlib.command.grep.flags_not_string = As flags do grep devem ser strings. +stdlib.command.quote.invalid = Não foi possível colocar { $arg } entre aspas: { $details }. +stdlib.command.quote.line_break = Argumentos com retornos de carro ou quebras de linha não podem ser protegidos com segurança. +stdlib.command.input_undefined = O valor de entrada não está definido. +stdlib.command.tempfile.root_required = A raiz do workspace é necessária para criar arquivos temporários de comandos. +stdlib.command.tempfile.create_failed = Não foi possível criar o arquivo temporário do comando: { $details }. +stdlib.command.options.invalid_utf8 = A chave de uma opção do comando deve ser UTF-8 válido. +stdlib.command.option.mode_not_string = O modo de saída deve ser uma string. +stdlib.command.options.invalid_type = As opções do comando devem ser um objeto. +stdlib.command.output.mode_unsupported = Modo de saída sem suporte "{ $mode }". +stdlib.command.output.mode.capture = captura +stdlib.command.output.mode.streaming = streaming +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Diagnósticos do auxiliar de caminhos. +stdlib.path.io.failed = { $action } falhou para { $path } ({ $label }). +stdlib.path.io.failed_with_detail = { $action } falhou para { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = { $action } falhou para { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = não encontrado +stdlib.path.io.permission_denied = permissão negada +stdlib.path.io.already_exists = já existe +stdlib.path.io.invalid_input = entrada inválida +stdlib.path.io.invalid_data = dados inválidos +stdlib.path.io.timed_out = tempo esgotado +stdlib.path.io.interrupted = interrompido +stdlib.path.io.would_block = bloquearia +stdlib.path.io.write_zero = nenhum byte foi gravado +stdlib.path.io.unexpected_eof = fim de arquivo inesperado +stdlib.path.io.broken_pipe = pipe quebrado +stdlib.path.io.connection_refused = conexão recusada +stdlib.path.io.connection_reset = conexão redefinida +stdlib.path.io.connection_aborted = conexão abortada +stdlib.path.io.not_connected = sem conexão +stdlib.path.io.addr_in_use = endereço em uso +stdlib.path.io.addr_not_available = endereço indisponível +stdlib.path.io.out_of_memory = sem memória +stdlib.path.io.unsupported = sem suporte +stdlib.path.io.file_too_large = arquivo grande demais +stdlib.path.io.resource_busy = recurso ocupado +stdlib.path.io.executable_busy = executável ocupado +stdlib.path.io.deadlock = impasse +stdlib.path.io.crosses_devices = cruza dispositivos +stdlib.path.io.too_many_links = links em excesso +stdlib.path.io.invalid_filename = nome de arquivo inválido +stdlib.path.io.arg_list_too_long = lista de argumentos longa demais +stdlib.path.io.stale_handle = identificador de arquivo de rede obsoleto +stdlib.path.io.storage_full = armazenamento cheio +stdlib.path.io.not_seekable = não permite posicionamento +stdlib.path.io.network_down = rede fora do ar +stdlib.path.io.network_unreachable = rede inacessível +stdlib.path.io.host_unreachable = host inacessível +stdlib.path.io.other = erro de E/S +stdlib.path.action.canonicalize = canonizar +stdlib.path.action.open_directory = abrir o diretório +stdlib.path.action.stat = consultar +stdlib.path.action.read = ler +stdlib.path.action.open_file = abrir o arquivo +stdlib.path.with_suffix.empty_separator = with_suffix exige um separador não vazio. +stdlib.path.relative_to.mismatch = { $path } não é relativo a { $root }. +stdlib.path.expanduser.unsupported = A expansão de ~ para um usuário específico não tem suporte. +stdlib.path.expanduser.no_home = Não é possível expandir ~: nenhuma variável de ambiente do diretório pessoal está definida. +stdlib.path.contents.unsupported_encoding = Codificação sem suporte "{ $encoding }". +stdlib.path.hash.unsupported_algorithm = Algoritmo de hash sem suporte "{ $algorithm }". +stdlib.path.hash.unsupported_algorithm_legacy = Algoritmo de hash sem suporte "{ $algorithm }" (habilite o recurso "{ $feature }"). + +# Diagnósticos dos auxiliares de coleções. +stdlib.collections.flatten.expected_sequence = O flatten esperava itens de uma sequência, mas encontrou { $kind }. +stdlib.collections.group_by.empty_attribute = O group_by exige um atributo não vazio. +stdlib.collections.group_by.unresolved = O group_by não conseguiu resolver "{ $attr }" em um item do tipo { $kind }. + +# Diagnósticos dos auxiliares de tempo. +stdlib.time.offset.invalid = O deslocamento de now "{ $offset }" é inválido: esperava-se "+HH:MM[:SS]" ou "Z". +stdlib.time.timedelta.overflow = Estouro de timedelta ao somar { $component }. +stdlib.time.label.weeks = semanas +stdlib.time.label.days = dias +stdlib.time.label.hours = horas +stdlib.time.label.minutes = minutos +stdlib.time.label.seconds = segundos +stdlib.time.label.milliseconds = milissegundos +stdlib.time.label.microseconds = microssegundos +stdlib.time.label.nanoseconds = nanossegundos + +# Diagnósticos do auxiliar which. +stdlib.which.not_found = [netsuke::jinja::which::not_found] comando "{ $command }" não encontrado após verificar { $count } entradas do PATH. Prévia: { $preview } +stdlib.which.not_found.hint.cwd_auto = Segmentos vazios do PATH são ignorados; use cwd_mode="auto" para incluir o diretório de trabalho. +stdlib.which.not_found.hint.cwd_always = Defina cwd_mode="always" para incluir o diretório atual. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] o comando "{ $command }" em "{ $path }" não existe ou não é executável. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = A entrada nº { $index } do PATH contém caracteres que não são UTF-8; o Netsuke exige caminhos UTF-8. +stdlib.which.command.empty = O which exige uma string não vazia. +stdlib.which.cwd_mode.invalid = cwd_mode deve ser "auto", "always" ou "never", obteve-se "{ $mode }". +stdlib.which.cwd.resolve_failed = Não foi possível resolver o diretório atual: { $details }. +stdlib.which.cwd.non_utf8 = O diretório atual contém componentes que não são UTF-8. +stdlib.which.canonicalize_failed = Não foi possível canonizar "{ $path }": { $details }. +stdlib.which.is_executable = Não foi possível verificar se "{ $path }" é executável: { $details }. +stdlib.which.canonicalize_non_utf8 = O caminho canônico contém componentes que não são UTF-8. +stdlib.which.workspace_non_utf8 = O caminho do workspace contém componentes que não são UTF-8 ao resolver o comando "{ $command }": { $path }. +stdlib.which.walkdir_error = Erro ao percorrer o workspace durante a resolução do comando: { $details }. + +# Registro da biblioteca padrão. +stdlib.register.open_dir = Não foi possível abrir o diretório atual para o registro da stdlib. +stdlib.register.resolve_dir = Não foi possível resolver o diretório atual para o registro da stdlib. +stdlib.register.dir_non_utf8 = O diretório atual contém componentes que não são UTF-8: { $path }. + +# Relatório de status para o modo de saída acessível. +status.state.pending = pendente +status.state.running = em andamento +status.state.done = concluída +status.state.failed = falhou +status.stage.label = Etapa { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Tarefa { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Lendo o arquivo de manifesto +status.stage.initial_yaml_parsing = Analisando o documento YAML +status.stage.template_expansion = Expandindo as diretivas dos templates +status.stage.final_rendering = Desserializando e renderizando os valores do manifesto +status.stage.ir_generation_validation = Construindo e validando o grafo de dependências +status.stage.ninja_synthesis = Sintetizando o plano de build do Ninja +status.stage.ninja_synthesis_execute = Sintetizando o plano do Ninja e executando { $tool } +status.stage.graph_rendering = Renderizando o artefato do grafo +status.stage.graph_rendering_with_tool = Renderizando { $tool } +status.complete = { $tool }: operação concluída. +status.timing.summary_header = Resumo de tempos por etapa: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Tempo total do pipeline: { $duration } +status.tool.build = Build +status.tool.clean = Limpeza +status.tool.graph = Grafo +status.tool.graph_html = Grafo (HTML) +status.tool.generate = Geração + +# Textos do renderizador HTML do grafo. +graph.html.title = Grafo de build do Netsuke +graph.html.heading = Grafo de build do Netsuke +graph.html.description = Grafo de build renderizado pelo Netsuke +graph.html.outline.summary = Alvos e dependências (esboço em texto) +graph.html.outline.no_inputs = Sem entradas +graph.html.noscript.notice = O JavaScript está desativado. O esboço em texto acima contém o grafo completo; o código DOT vem a seguir. + +# Prefixos semânticos para a saída acessível. +semantic.prefix.error = Erro: +semantic.prefix.warning = Aviso: +semantic.prefix.success = Sucesso: +semantic.prefix.info = Info: +semantic.prefix.timing = Tempos: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Exemplos de formas plurais para tradutores. +# O português usa as categorias CLDR `one` e `other`, assim como o idioma +# de origem. +example.files_processed = { $count -> + [one] { $count } arquivo processado. + *[other] { $count } arquivos processados. +} + +example.errors_found = { $count -> + [0] Nenhum erro encontrado. + [one] { $count } erro encontrado. + *[other] { $count } erros encontrados. +} diff --git a/locales/pt-PT/messages.ftl b/locales/pt-PT/messages.ftl new file mode 100644 index 000000000..da39c586b --- /dev/null +++ b/locales/pt-PT/messages.ftl @@ -0,0 +1,399 @@ +# Recursos de localização para a CLI do Netsuke (português europeu). + +cli.about = O Netsuke compila manifestos YAML + Jinja em planos de compilação Ninja. +cli.long_about = O Netsuke transforma manifestos YAML + Jinja em grafos Ninja reprodutíveis e executa o Ninja com predefinições seguras. +cli.usage = { $usage } + +# Texto de ajuda das opções globais. +cli.flag.file.help = Caminho para o ficheiro de manifesto do Netsuke a utilizar. +cli.flag.directory.help = Executar como se tivesse sido iniciado nesta pasta. +cli.flag.config.help = Caminho para um ficheiro de configuração, ignorando a deteção automática. +cli.flag.jobs.help = Definir o número de tarefas de compilação em paralelo. +cli.flag.verbose.help = Ativar registos de diagnóstico detalhados e resumos de tempos no final. +cli.flag.locale.help = Etiqueta de idioma para os textos da CLI (por exemplo: en-US, pt-PT). +cli.flag.fetch_allow_scheme.help = Esquemas de URL adicionais permitidos para o auxiliar fetch. +cli.flag.fetch_allow_host.help = Nomes de anfitrião permitidos quando a recusa predefinida está ativa. +cli.flag.fetch_block_host.help = Nomes de anfitrião sempre bloqueados, mesmo que permitidos noutro local. +cli.flag.fetch_default_deny.help = Recusar todos os anfitriões por predefinição; permitir apenas a lista declarada. +cli.flag.json.help = Produzir saída JSON legível por máquinas. +cli.flag.no_input.help = Nunca ler entrada interativa. +cli.flag.color.help = Política de cor na saída (auto, always, never). +cli.flag.emoji.help = Política de emojis (auto, always, never). +cli.flag.progress.help = Política de apresentação do progresso (auto, always, never). +cli.flag.accessibility.help = Política de saída acessível (auto, on, off). +cli.flag.default_targets.help = Alvos de compilação predefinidos quando nenhum é indicado. + +# Descrições dos subcomandos. +cli.subcommand.build.about = Compilar os alvos definidos no manifesto (predefinição). +cli.subcommand.build.long_about = Compilar os alvos pedidos; se nenhum for indicado, usar os predefinidos do manifesto. +cli.subcommand.clean.about = Remover os artefactos de compilação através do Ninja. +cli.subcommand.clean.long_about = Gerar um ficheiro Ninja temporário e depois executar `ninja -t clean`. +cli.subcommand.graph.about = Emitir o grafo de dependências de compilação. O formato predefinido é DOT. +cli.subcommand.graph.long_about = Projetar o manifesto do Netsuke analisado num grafo de compilação canónico e escrevê-lo como Graphviz DOT, ou como página HTML autónoma com `--html`. Use `--output ` para escrever num ficheiro; `-` escreve no stdout. +cli.subcommand.generate.about = Gerar o manifesto Ninja sem executar o Ninja. +cli.subcommand.generate.long_about = Escrever o manifesto Ninja gerado no stdout ou num ficheiro escolhido com `--output`. + +# Texto de ajuda das opções do subcomando build. +cli.subcommand.build.flag.targets.help = Alvos a compilar (se omitido, usa os predefinidos do manifesto). + +# Texto de ajuda das opções do subcomando graph. +cli.subcommand.graph.flag.html.help = Representar o grafo como página HTML autónoma em vez de DOT. +cli.subcommand.graph.flag.output.help = Escrever o artefacto do grafo em FICHEIRO; use `-` para o stdout. + +# Texto de ajuda das opções do subcomando generate. +cli.subcommand.generate.flag.output.help = Escrever o manifesto Ninja gerado em FICHEIRO em vez do stdout. + +# Erros de validação da CLI. +cli.validation.jobs.invalid_number = { $value } não é um número válido. +cli.validation.jobs.out_of_range = O número de tarefas tem de estar entre { $min } e { $max }. +cli.validation.scheme.empty = O esquema não pode estar vazio. +cli.validation.scheme.invalid_start = O esquema «{ $scheme }» tem de começar por uma letra ASCII. +cli.validation.scheme.invalid = Esquema inválido «{ $scheme }». +cli.validation.locale.empty = A etiqueta de idioma não pode estar vazia. +cli.validation.locale.invalid = Etiqueta de idioma inválida «{ $locale }». +cli.validation.color.invalid = Política de cor inválida «{ $value }». Opções válidas: auto, always, never. +cli.validation.emoji.invalid = Política de emojis inválida «{ $value }». Opções válidas: auto, always, never. +cli.validation.progress.invalid = Política de progresso inválida «{ $value }». Opções válidas: auto, always, never. +cli.validation.accessibility.invalid = Política de acessibilidade inválida «{ $value }». Opções válidas: auto, on, off. +cli.validation.config.expected_object = Esperava-se que os valores da CLI fossem serializados como objeto, obteve-se { $value }. + +# Mensagens de erro do Clap. +clap-error-missing-argument = Falta um argumento obrigatório: { $argument } +clap-error-missing-subcommand = Falta o subcomando. Opções disponíveis: { $valid_subcommands } +clap-error-unknown-argument = Argumento desconhecido: { $argument } +clap-error-invalid-value = Valor inválido para { $argument }: { $value } +clap-error-invalid-subcommand = Subcomando desconhecido: { $subcommand } +# Nota: value-validation usa uma formulação distinta de invalid-value para +# diferenciar falhas de validadores personalizados +# (ErrorKind::ValueValidation) de incompatibilidades de tipo +# (ErrorKind::InvalidValue). +clap-error-value-validation = A validação falhou para { $argument }: { $value } + +# Erros e contextos do executor. +runner.manifest.not_found = Manifesto «{ $manifest_name }» não encontrado em { $directory }. +runner.manifest.not_found.help = Confirme que o manifesto existe ou indique `--file` com o caminho correto. +runner.manifest.path_missing_name = O caminho do manifesto «{ $path }» não tem nome de ficheiro. +runner.manifest.path_utf8 = O caminho do manifesto «{ $path }» não é UTF-8 válido. +runner.manifest.directory_utf8 = O caminho da pasta do manifesto «{ $path }» não é UTF-8 válido. +runner.manifest.directory_label = pasta `{ $directory }` +runner.manifest.current_directory_label = a pasta atual +runner.context.network_policy = Não foi possível construir a política de rede. +runner.context.load_manifest = Não foi possível carregar o manifesto em { $path }. +runner.context.serialise_manifest = Não foi possível serializar o manifesto. +runner.context.build_graph = Não foi possível construir o grafo a partir do manifesto. +runner.context.generate_ninja = Não foi possível gerar o manifesto Ninja. +runner.context.render_graph = Não foi possível representar o artefacto do grafo. + +runner.io.create_temp_file = Não foi possível criar o ficheiro Ninja temporário. +runner.io.write_temp_ninja = Não foi possível escrever o ficheiro Ninja temporário. +runner.io.flush_temp_ninja = Não foi possível esvaziar o buffer do ficheiro Ninja temporário. +runner.io.sync_temp_ninja = Não foi possível sincronizar o ficheiro Ninja temporário. +runner.io.create_parent_dir = Não foi possível criar a pasta principal { $path }. +runner.io.create_ninja_file = Não foi possível criar o ficheiro Ninja em { $path }. +runner.io.write_ninja_file = Não foi possível escrever o ficheiro Ninja em { $path }. +runner.io.flush_ninja_file = Não foi possível esvaziar o buffer do ficheiro Ninja em { $path }. +runner.io.sync_ninja_file = Não foi possível sincronizar o ficheiro Ninja em { $path }. +runner.io.open_ambient_dir = Não foi possível abrir a pasta do ambiente. +runner.io.no_existing_ancestor = Não existe nenhuma pasta ascendente para { $path }. +runner.io.derive_relative_path = Não foi possível derivar o caminho Ninja relativo. +runner.io.non_utf8_path = Não são suportados caminhos que não sejam UTF-8 (caminho: { $path }). +runner.io.write_stdout = Não foi possível escrever o manifesto Ninja no stdout. +runner.io.flush_stdout = Não foi possível esvaziar o buffer do stdout. + +# Diagnósticos do manifesto. +manifest.parse = A análise do manifesto falhou. +manifest.structure_error = Erro de estrutura do manifesto em { $name }: { $details } +manifest.yaml.parse = Erro de análise YAML na linha { $line }, coluna { $column }: { $details } +manifest.yaml.label = YAML inválido +manifest.yaml.hint.tabs = O YAML não permite tabulações; use espaços na indentação. +manifest.yaml.hint.list_item = Os itens de lista YAML têm de começar por «-» e estar corretamente indentados. +manifest.yaml.hint.expected_colon = Isto parece uma entrada de mapeamento; falta «:» depois da chave. +manifest.yaml.hint.mapping_values = Os mapeamentos YAML exigem um valor depois de «:» (ou um bloco aninhado). +manifest.yaml.hint.invalid_token = O símbolo YAML é inválido ou inesperado. +manifest.yaml.hint.escape = Faça o escape das barras invertidas ou remova as sequências de escape inválidas. +manifest.env.missing = A variável de ambiente obrigatória «{ $name }» não está definida. +manifest.env.invalid_utf8 = A variável de ambiente «{ $name }» contém UTF-8 inválido. +manifest.vars.not_object = `vars` do manifesto tem de ser um mapa ou objeto. +manifest.read_failed = Não foi possível ler o manifesto em { $path }. +manifest.resolve_workspace_root = Não foi possível resolver a raiz da área de trabalho. +manifest.workspace_non_utf8 = O caminho de raiz da área de trabalho «{ $path }» não é UTF-8 válido. +manifest.path_non_utf8 = O caminho do manifesto «{ $manifest }» não é UTF-8 válido: { $path }. +manifest.path_missing_name = O caminho do manifesto «{ $path }» não tem nome de ficheiro. +manifest.open_workspace_failed = Não foi possível abrir a área de trabalho { $workspace } para o manifesto { $manifest }. +manifest.foreach.not_iterable = A expressão `foreach` não é iterável. +manifest.foreach.serialise_item = Não foi possível serializar o item de `foreach`. +manifest.when.empty = A expressão `when` não pode estar vazia. +manifest.when.eval_error = Não foi possível avaliar a expressão `when` «{ $expr }». +manifest.when.template_error = Não foi possível representar o modelo `when` «{ $expr }». +manifest.target.vars_not_object = `vars` do alvo tem de ser um objeto, obteve-se { $value }. +manifest.vars.entry_not_object = Uma entrada `vars` do manifesto tem de ser um objeto. +manifest.field_not_string = O campo «{ $field }» tem de ser uma cadeia de carateres. +manifest.expression.parse_error = Não foi possível analisar a expressão { $name }. +manifest.expression.eval_error = Não foi possível avaliar a expressão { $name }. + +# Diagnósticos das macros do manifesto. +manifest.macro.signature_missing_identifier = Falta um identificador na assinatura da macro. +manifest.macro.signature_missing_params = Faltam parâmetros na assinatura da macro. +manifest.macro.compile_failed = Não foi possível compilar a macro { $name }. +manifest.macro.sequence_invalid = As macros têm de ser definidas como um mapeamento de nomes para modelos. +manifest.macro.register_failed = Não foi possível registar as macros do manifesto. +manifest.macro.not_initialised = O ambiente de macros não está inicializado. +manifest.macro.caller_invalid = O invocador da macro tem de ser uma cadeia de carateres. +manifest.macro.template_load_failed = Não foi possível carregar o modelo da macro. +manifest.macro.init_failed = Não foi possível inicializar o ambiente de macros. +manifest.macro.missing = Falta a macro { $name }. + +# Erros de glob do manifesto. +manifest.glob.unmatched_brace = Padrão glob inválido «{ $pattern }»: «{ $character }» sem correspondência na posição { $position }. +manifest.glob.invalid_pattern = Padrão glob inválido «{ $pattern }»: { $detail }. +manifest.glob.unknown_pattern_error = erro de padrão desconhecido. +manifest.glob.io_failed = O glob falhou para «{ $pattern }»: { $detail }. +manifest.glob.unknown_io_error = erro de E/S desconhecido. + +# Erros da representação intermédia. +ir.rule_not_found = A regra «{ $rule }» referenciada pelo alvo «{ $target }» não foi encontrada. +ir.multiple_rules = O alvo «{ $target }» tem de referenciar uma única regra, obteve-se { $rules }. +ir.empty_rule = O alvo «{ $target }» tem de referenciar uma regra. +ir.duplicate_outputs = Foram detetadas saídas duplicadas: { $outputs }. +ir.circular_dependency = Foi detetada uma dependência circular: { $cycle }. +ir.action_serialisation = Não foi possível serializar a ação: { $details }. +ir.invalid_command = Interpolação de comando inválida: { $snippet }. + +# Erros de geração do Ninja. +ninja_gen.missing_action = Falta a ação «{ $id }» referenciada por uma aresta de compilação. +ninja_gen.format = Não foi possível formatar a saída do manifesto Ninja. + +# Validação de padrões de anfitrião. +host_pattern.empty = O padrão de anfitrião não pode estar vazio. +host_pattern.contains_scheme = O padrão de anfitrião «{ $pattern }» não pode incluir um esquema de URL. +host_pattern.contains_slash = O padrão de anfitrião «{ $pattern }» não pode incluir «/». +host_pattern.missing_suffix = O padrão de anfitrião «{ $pattern }» tem de incluir um sufixo depois de «*.». +host_pattern.empty_label = O padrão de anfitrião «{ $pattern }» contém uma etiqueta vazia. +host_pattern.invalid_chars = O padrão de anfitrião «{ $pattern }» contém carateres inválidos. +host_pattern.invalid_label_edge = As etiquetas do padrão de anfitrião «{ $pattern }» não podem começar nem terminar por «-». +host_pattern.label_too_long = O padrão de anfitrião «{ $pattern }» contém uma etiqueta com mais de 63 carateres. +host_pattern.too_long = O padrão de anfitrião «{ $pattern }» excede o limite de 255 carateres. + +# Política de rede. +network_policy.scheme.empty = O esquema não pode estar vazio. +network_policy.scheme.invalid = O esquema «{ $scheme }» contém carateres inválidos. +network_policy.allowlist.empty = A lista de anfitriões permitidos não pode estar vazia. +network_policy.scheme.not_allowed = O esquema «{ $scheme }» não é permitido. +network_policy.missing_host = Falta o anfitrião no URL. +network_policy.host.blocked = O anfitrião «{ $host }» está bloqueado pela política. +network_policy.host.not_allowlisted = O anfitrião «{ $host }» não consta da lista de permitidos. + +# Configuração da biblioteca padrão. +stdlib.config.default_fetch_cache_invalid = O caminho predefinido da cache do fetch tem de ser relativo. +stdlib.config.default_which_cache_invalid = A capacidade predefinida da cache do which tem de ser positiva. +stdlib.config.workspace_root_absolute = O caminho de raiz da área de trabalho tem de ser absoluto. +stdlib.config.fetch_response_limit_positive = O limite de resposta do fetch tem de ser positivo. +stdlib.config.command_output_limit_positive = O limite de captura da saída dos comandos tem de ser positivo. +stdlib.config.command_stream_limit_positive = O limite de fluxo dos comandos tem de ser positivo. +stdlib.config.which_cache_capacity_positive = A capacidade da cache do which tem de ser positiva. +stdlib.config.skip_dir_empty = As entradas de pastas a ignorar não podem estar vazias. +stdlib.config.skip_dir_navigation = As entradas de pastas a ignorar não podem conter «..». +stdlib.config.skip_dir_separator = As entradas de pastas a ignorar não podem conter separadores de caminho. +stdlib.config.fetch_cache_empty = O caminho da cache do fetch não pode estar vazio. +stdlib.config.fetch_cache_not_relative = O caminho da cache do fetch tem de ser relativo, obteve-se { $path }. +stdlib.config.fetch_cache_escapes = O caminho da cache do fetch não pode sair da área de trabalho: { $path }. +stdlib.config.open_workspace_root = Não foi possível abrir a pasta atual como raiz da área de trabalho da stdlib. +stdlib.config.resolve_cwd = Não foi possível resolver a pasta atual como raiz da área de trabalho da stdlib. +stdlib.config.cwd_non_utf8 = A pasta atual contém componentes que não são UTF-8: { $path }. + +# Diagnósticos do auxiliar fetch. +stdlib.fetch.url_invalid = URL inválido «{ $url }»: { $details }. +stdlib.fetch.disallowed = O URL «{ $url }» não é permitido: { $details }. +stdlib.fetch.failed = Não foi possível obter «{ $url }»: { $details }. +stdlib.fetch.cache_read_failed = Não foi possível ler a entrada de cache «{ $name }»: { $details }. +stdlib.fetch.cache_open_failed = Não foi possível abrir a entrada de cache «{ $name }»: { $details }. +stdlib.fetch.response_read_failed = Não foi possível ler a resposta de «{ $url }»: { $details }. +stdlib.fetch.response_buffer_overflow = Transbordamento do buffer ao ler «{ $url }». +stdlib.fetch.cache_write_failed = Não foi possível escrever a cache para «{ $url }»: { $details }. +stdlib.fetch.response_limit_exceeded = A resposta de «{ $url }» excedeu o limite de { $limit } bytes. +stdlib.fetch.cache_limit_exceeded = A resposta em cache «{ $name }» excedeu o limite de { $limit } bytes. +stdlib.fetch.io_failed = { $action } falhou para { $path }: { $details }. +stdlib.fetch.action.sync_cache = sincronizar a cache do fetch +stdlib.fetch.action.create_cache_dir = criar a pasta de cache do fetch +stdlib.fetch.action.open_cache_dir = abrir a pasta de cache do fetch +stdlib.fetch.action.stat_cache = consultar a entrada de cache do fetch +stdlib.fetch.action.open_cache_entry = abrir a entrada de cache do fetch + +# Diagnósticos do auxiliar de comandos. +stdlib.command.location = comando «{ $command }» no modelo «{ $template }» +stdlib.command.spawn_failed = Não foi possível iniciar { $location }: { $details }. +stdlib.command.io_failed = { $location } falhou: { $details }. +stdlib.command.closed_input_early = A entrada fechou antes de concluir a escrita para o comando. +stdlib.command.broken_pipe = Canal quebrado ao executar { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } foi terminado por um sinal. +stdlib.command.exited_with_status = { $location } terminou com o estado { $status }. +stdlib.command.output_limit_exceeded = { $location } excedeu o limite de { $mode } de { $limit } bytes para { $stream }. +stdlib.command.timeout = { $location } excedeu o tempo-limite de { $seconds } segundos. +stdlib.command.exit_status_suffix = (estado de saída { $status }) +stdlib.command.signal_suffix = (terminado por um sinal) +stdlib.command.shell.empty = O comando de shell não pode estar vazio. +stdlib.command.grep.empty_pattern = O padrão do grep não pode estar vazio. +stdlib.command.grep.flags_not_string = As opções do grep têm de ser cadeias de carateres. +stdlib.command.quote.invalid = Não foi possível colocar { $arg } entre aspas: { $details }. +stdlib.command.quote.line_break = Os argumentos com retornos de carro ou quebras de linha não podem ser colocados entre aspas com segurança. +stdlib.command.input_undefined = O valor de entrada não está definido. +stdlib.command.tempfile.root_required = É necessária a raiz da área de trabalho para criar ficheiros temporários de comandos. +stdlib.command.tempfile.create_failed = Não foi possível criar o ficheiro temporário do comando: { $details }. +stdlib.command.options.invalid_utf8 = A chave de uma opção do comando tem de ser UTF-8 válido. +stdlib.command.option.mode_not_string = O modo de saída tem de ser uma cadeia de carateres. +stdlib.command.options.invalid_type = As opções do comando têm de ser um objeto. +stdlib.command.output.mode_unsupported = Modo de saída não suportado «{ $mode }». +stdlib.command.output.mode.capture = captura +stdlib.command.output.mode.streaming = fluxo contínuo +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Diagnósticos do auxiliar de caminhos. +stdlib.path.io.failed = { $action } falhou para { $path } ({ $label }). +stdlib.path.io.failed_with_detail = { $action } falhou para { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = { $action } falhou para { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = não encontrado +stdlib.path.io.permission_denied = permissão negada +stdlib.path.io.already_exists = já existe +stdlib.path.io.invalid_input = entrada inválida +stdlib.path.io.invalid_data = dados inválidos +stdlib.path.io.timed_out = tempo esgotado +stdlib.path.io.interrupted = interrompido +stdlib.path.io.would_block = bloquearia +stdlib.path.io.write_zero = não foi escrito nenhum byte +stdlib.path.io.unexpected_eof = fim de ficheiro inesperado +stdlib.path.io.broken_pipe = canal quebrado +stdlib.path.io.connection_refused = ligação recusada +stdlib.path.io.connection_reset = ligação reposta +stdlib.path.io.connection_aborted = ligação abortada +stdlib.path.io.not_connected = sem ligação +stdlib.path.io.addr_in_use = endereço em utilização +stdlib.path.io.addr_not_available = endereço indisponível +stdlib.path.io.out_of_memory = sem memória +stdlib.path.io.unsupported = não suportado +stdlib.path.io.file_too_large = ficheiro demasiado grande +stdlib.path.io.resource_busy = recurso ocupado +stdlib.path.io.executable_busy = executável ocupado +stdlib.path.io.deadlock = impasse +stdlib.path.io.crosses_devices = atravessa dispositivos +stdlib.path.io.too_many_links = demasiadas ligações +stdlib.path.io.invalid_filename = nome de ficheiro inválido +stdlib.path.io.arg_list_too_long = lista de argumentos demasiado longa +stdlib.path.io.stale_handle = identificador de ficheiro de rede obsoleto +stdlib.path.io.storage_full = armazenamento cheio +stdlib.path.io.not_seekable = não permite posicionamento +stdlib.path.io.network_down = rede em baixo +stdlib.path.io.network_unreachable = rede inacessível +stdlib.path.io.host_unreachable = anfitrião inacessível +stdlib.path.io.other = erro de E/S +stdlib.path.action.canonicalize = canonizar +stdlib.path.action.open_directory = abrir a pasta +stdlib.path.action.stat = consultar +stdlib.path.action.read = ler +stdlib.path.action.open_file = abrir o ficheiro +stdlib.path.with_suffix.empty_separator = with_suffix exige um separador não vazio. +stdlib.path.relative_to.mismatch = { $path } não é relativo a { $root }. +stdlib.path.expanduser.unsupported = A expansão de ~ para um utilizador específico não é suportada. +stdlib.path.expanduser.no_home = Não é possível expandir ~: não há variáveis de ambiente da pasta pessoal definidas. +stdlib.path.contents.unsupported_encoding = Codificação não suportada «{ $encoding }». +stdlib.path.hash.unsupported_algorithm = Algoritmo de hash não suportado «{ $algorithm }». +stdlib.path.hash.unsupported_algorithm_legacy = Algoritmo de hash não suportado «{ $algorithm }» (ative a funcionalidade «{ $feature }»). + +# Diagnósticos dos auxiliares de coleções. +stdlib.collections.flatten.expected_sequence = O flatten esperava itens de uma sequência, mas encontrou { $kind }. +stdlib.collections.group_by.empty_attribute = O group_by exige um atributo não vazio. +stdlib.collections.group_by.unresolved = O group_by não conseguiu resolver «{ $attr }» num item do tipo { $kind }. + +# Diagnósticos dos auxiliares de tempo. +stdlib.time.offset.invalid = O desvio de now «{ $offset }» é inválido: esperava-se «+HH:MM[:SS]» ou «Z». +stdlib.time.timedelta.overflow = Sobrecarga de timedelta ao adicionar { $component }. +stdlib.time.label.weeks = semanas +stdlib.time.label.days = dias +stdlib.time.label.hours = horas +stdlib.time.label.minutes = minutos +stdlib.time.label.seconds = segundos +stdlib.time.label.milliseconds = milissegundos +stdlib.time.label.microseconds = microssegundos +stdlib.time.label.nanoseconds = nanossegundos + +# Diagnósticos do auxiliar which. +stdlib.which.not_found = [netsuke::jinja::which::not_found] comando «{ $command }» não encontrado após verificar { $count } entradas do PATH. Pré-visualização: { $preview } +stdlib.which.not_found.hint.cwd_auto = Os segmentos vazios do PATH são ignorados; use cwd_mode="auto" para incluir a pasta de trabalho. +stdlib.which.not_found.hint.cwd_always = Defina cwd_mode="always" para incluir a pasta atual. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] o comando «{ $command }» em «{ $path }» não existe ou não é executável. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = A entrada n.º { $index } do PATH contém carateres que não são UTF-8; o Netsuke exige caminhos UTF-8. +stdlib.which.command.empty = O which exige uma cadeia de carateres não vazia. +stdlib.which.cwd_mode.invalid = cwd_mode tem de ser «auto», «always» ou «never», obteve-se «{ $mode }». +stdlib.which.cwd.resolve_failed = Não foi possível resolver a pasta atual: { $details }. +stdlib.which.cwd.non_utf8 = A pasta atual contém componentes que não são UTF-8. +stdlib.which.canonicalize_failed = Não foi possível canonizar «{ $path }»: { $details }. +stdlib.which.is_executable = Não foi possível verificar se «{ $path }» é executável: { $details }. +stdlib.which.canonicalize_non_utf8 = O caminho canónico contém componentes que não são UTF-8. +stdlib.which.workspace_non_utf8 = O caminho da área de trabalho contém componentes que não são UTF-8 ao resolver o comando «{ $command }»: { $path }. +stdlib.which.walkdir_error = Erro ao percorrer a área de trabalho durante a resolução do comando: { $details }. + +# Registo da biblioteca padrão. +stdlib.register.open_dir = Não foi possível abrir a pasta atual para o registo da stdlib. +stdlib.register.resolve_dir = Não foi possível resolver a pasta atual para o registo da stdlib. +stdlib.register.dir_non_utf8 = A pasta atual contém componentes que não são UTF-8: { $path }. + +# Relatório de estado para o modo de saída acessível. +status.state.pending = pendente +status.state.running = em curso +status.state.done = concluída +status.state.failed = falhou +status.stage.label = Fase { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Tarefa { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = A ler o ficheiro de manifesto +status.stage.initial_yaml_parsing = A analisar o documento YAML +status.stage.template_expansion = A expandir as diretivas dos modelos +status.stage.final_rendering = A desserializar e representar os valores do manifesto +status.stage.ir_generation_validation = A construir e validar o grafo de dependências +status.stage.ninja_synthesis = A sintetizar o plano de compilação Ninja +status.stage.ninja_synthesis_execute = A sintetizar o plano Ninja e a executar { $tool } +status.stage.graph_rendering = A representar o artefacto do grafo +status.stage.graph_rendering_with_tool = A representar { $tool } +status.complete = { $tool }: operação concluída. +status.timing.summary_header = Resumo de tempos por fase: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Tempo total do pipeline: { $duration } +status.tool.build = Compilação +status.tool.clean = Limpeza +status.tool.graph = Grafo +status.tool.graph_html = Grafo (HTML) +status.tool.generate = Geração + +# Cadeias do representador HTML do grafo. +graph.html.title = Grafo de compilação do Netsuke +graph.html.heading = Grafo de compilação do Netsuke +graph.html.description = Grafo de compilação representado pelo Netsuke +graph.html.outline.summary = Alvos e dependências (esquema textual) +graph.html.outline.no_inputs = Sem entradas +graph.html.noscript.notice = O JavaScript está desativado. O esquema textual acima contém o grafo completo; segue-se o código DOT. + +# Prefixos semânticos para a saída acessível. +semantic.prefix.error = Erro: +semantic.prefix.warning = Aviso: +semantic.prefix.success = Sucesso: +semantic.prefix.info = Info: +semantic.prefix.timing = Tempos: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Exemplos de formas plurais para tradutores. +# O português usa as categorias CLDR `one` e `other`, tal como o idioma +# de origem. +example.files_processed = { $count -> + [one] Foi processado { $count } ficheiro. + *[other] Foram processados { $count } ficheiros. +} + +example.errors_found = { $count -> + [0] Não foram encontrados erros. + [one] Foi encontrado { $count } erro. + *[other] Foram encontrados { $count } erros. +} diff --git a/locales/ro/messages.ftl b/locales/ro/messages.ftl new file mode 100644 index 000000000..9ff49155f --- /dev/null +++ b/locales/ro/messages.ftl @@ -0,0 +1,401 @@ +# Resurse de localizare pentru linia de comandă Netsuke. + +cli.about = Netsuke compilează manifeste YAML + Jinja în planuri de construire Ninja. +cli.long_about = Netsuke transformă manifestele YAML + Jinja în grafuri Ninja reproductibile și rulează Ninja cu valori implicite sigure. +cli.usage = { $usage } + +# Textul de ajutor pentru opțiunile globale. +cli.flag.file.help = Calea către fișierul de manifest Netsuke care va fi folosit. +cli.flag.directory.help = Rulează ca și cum pornirea ar fi avut loc în acest director. +cli.flag.config.help = Calea către un fișier de configurare, ocolind căutarea automată. +cli.flag.jobs.help = Stabilește numărul de sarcini de construire care rulează în paralel. +cli.flag.verbose.help = Activează jurnalizarea de diagnostic detaliată și rezumatele de timp la final. +cli.flag.locale.help = Eticheta de limbă pentru textele liniei de comandă (de exemplu: en-US, ro). +cli.flag.fetch_allow_scheme.help = Scheme URL suplimentare permise pentru ajutorul fetch. +cli.flag.fetch_allow_host.help = Numele de gazde permise atunci când refuzul implicit este activ. +cli.flag.fetch_block_host.help = Numele de gazde blocate întotdeauna, chiar dacă sunt permise în altă parte. +cli.flag.fetch_default_deny.help = Refuză implicit toate gazdele; permite doar lista declarată. +cli.flag.json.help = Produce ieșire JSON care poate fi prelucrată automat. +cli.flag.no_input.help = Nu citi niciodată date introduse interactiv. +cli.flag.color.help = Politica de ieșire colorată (auto, always, never). +cli.flag.emoji.help = Politica pentru emoji (auto, always, never). +cli.flag.progress.help = Politica de afișare a progresului (auto, always, never). +cli.flag.accessibility.help = Politica de ieșire accesibilă (auto, on, off). +cli.flag.default_targets.help = Țintele de construire implicite când nu este indicată niciuna. + +# Descrierile subcomenzilor. +cli.subcommand.build.about = Construiește țintele definite în manifest (implicit). +cli.subcommand.build.long_about = Construiește țintele cerute; dacă nu este indicată niciuna, folosește țintele implicite din manifest. +cli.subcommand.clean.about = Elimină artefactele de construire prin Ninja. +cli.subcommand.clean.long_about = Generează un fișier Ninja temporar, apoi rulează `ninja -t clean`. +cli.subcommand.graph.about = Emite graful dependențelor de construire. Formatul implicit este DOT. +cli.subcommand.graph.long_about = Proiectează manifestul Netsuke analizat într-un graf de construire canonic și îl scrie ca Graphviz DOT sau, cu `--html`, ca pagină HTML de sine stătătoare. Folosiți `--output ` pentru a scrie într-un fișier; `-` scrie la ieșirea standard. +cli.subcommand.generate.about = Generează manifestul Ninja fără a rula Ninja. +cli.subcommand.generate.long_about = Scrie manifestul Ninja generat la ieșirea standard sau într-un fișier ales cu `--output`. + +# Textul de ajutor pentru opțiunile subcomenzii build. +cli.subcommand.build.flag.targets.help = Țintele de construit (dacă lipsesc, se folosesc cele implicite din manifest). + +# Textul de ajutor pentru opțiunile subcomenzii graph. +cli.subcommand.graph.flag.html.help = Redă graful ca pagină HTML de sine stătătoare în loc de format DOT. +cli.subcommand.graph.flag.output.help = Scrie artefactul grafului în FIȘIER; folosiți `-` pentru ieșirea standard. + +# Textul de ajutor pentru opțiunile subcomenzii generate. +cli.subcommand.generate.flag.output.help = Scrie manifestul Ninja generat în FIȘIER în loc de ieșirea standard. + +# Erori de validare la linia de comandă. +cli.validation.jobs.invalid_number = { $value } nu este un număr valid. +cli.validation.jobs.out_of_range = Numărul de sarcini trebuie să fie între { $min } și { $max }. +cli.validation.scheme.empty = Schema nu trebuie să fie goală. +cli.validation.scheme.invalid_start = Schema „{ $scheme }” trebuie să înceapă cu o literă ASCII. +cli.validation.scheme.invalid = Schemă nevalidă „{ $scheme }”. +cli.validation.locale.empty = Eticheta de limbă nu trebuie să fie goală. +cli.validation.locale.invalid = Etichetă de limbă nevalidă „{ $locale }”. +cli.validation.color.invalid = Politică de culoare nevalidă „{ $value }”. Opțiuni valide: auto, always, never. +cli.validation.emoji.invalid = Politică pentru emoji nevalidă „{ $value }”. Opțiuni valide: auto, always, never. +cli.validation.progress.invalid = Politică de progres nevalidă „{ $value }”. Opțiuni valide: auto, always, never. +cli.validation.accessibility.invalid = Politică de accesibilitate nevalidă „{ $value }”. Opțiuni valide: auto, on, off. +cli.validation.config.expected_object = Valorile liniei de comandă trebuiau serializate într-un obiect; s-a primit { $value }. + +# Mesajele de eroare din Clap. +clap-error-missing-argument = Lipsește un argument obligatoriu: { $argument } +clap-error-missing-subcommand = Lipsește subcomanda. Opțiuni disponibile: { $valid_subcommands } +clap-error-unknown-argument = Argument necunoscut: { $argument } +clap-error-invalid-value = Valoare nevalidă pentru { $argument }: { $value } +clap-error-invalid-subcommand = Subcomandă necunoscută: { $subcommand } +# Notă: value-validation este formulat diferit de invalid-value pentru a +# deosebi erorile validatoarelor proprii (ErrorKind::ValueValidation) de +# nepotrivirile de tip (ErrorKind::InvalidValue). +clap-error-value-validation = Validarea a eșuat pentru { $argument }: { $value } + +# Erori și context la execuție. +runner.manifest.not_found = Manifestul „{ $manifest_name }” nu a fost găsit în { $directory }. +runner.manifest.not_found.help = Verificați că manifestul există sau indicați `--file` cu calea corectă. +runner.manifest.path_missing_name = Calea manifestului „{ $path }” nu conține un nume de fișier. +runner.manifest.path_utf8 = Calea manifestului „{ $path }” nu este UTF-8 valid. +runner.manifest.directory_utf8 = Calea directorului manifestului „{ $path }” nu este UTF-8 valid. +runner.manifest.directory_label = directorul `{ $directory }` +runner.manifest.current_directory_label = directorul curent +runner.context.network_policy = Politica de rețea nu a putut fi construită. +runner.context.load_manifest = Manifestul din { $path } nu a putut fi încărcat. +runner.context.serialise_manifest = Manifestul nu a putut fi serializat. +runner.context.build_graph = Graful nu a putut fi construit din manifest. +runner.context.generate_ninja = Manifestul Ninja nu a putut fi generat. +runner.context.render_graph = Artefactul grafului nu a putut fi redat. + +runner.io.create_temp_file = Fișierul Ninja temporar nu a putut fi creat. +runner.io.write_temp_ninja = Fișierul Ninja temporar nu a putut fi scris. +runner.io.flush_temp_ninja = Memoria tampon a fișierului Ninja temporar nu a putut fi golită. +runner.io.sync_temp_ninja = Fișierul Ninja temporar nu a putut fi sincronizat. +runner.io.create_parent_dir = Directorul părinte { $path } nu a putut fi creat. +runner.io.create_ninja_file = Fișierul Ninja din { $path } nu a putut fi creat. +runner.io.write_ninja_file = Fișierul Ninja din { $path } nu a putut fi scris. +runner.io.flush_ninja_file = Memoria tampon a fișierului Ninja din { $path } nu a putut fi golită. +runner.io.sync_ninja_file = Fișierul Ninja din { $path } nu a putut fi sincronizat. +runner.io.open_ambient_dir = Directorul înconjurător nu a putut fi deschis. +runner.io.no_existing_ancestor = Pentru { $path } nu există niciun director părinte. +runner.io.derive_relative_path = Calea Ninja relativă nu a putut fi dedusă. +runner.io.non_utf8_path = Căile care nu sunt UTF-8 nu sunt acceptate (calea: { $path }). +runner.io.write_stdout = Manifestul Ninja nu a putut fi scris la ieșirea standard. +runner.io.flush_stdout = Memoria tampon a ieșirii standard nu a putut fi golită. + +# Diagnostice ale manifestului. +manifest.parse = Analiza manifestului a eșuat. +manifest.structure_error = Eroare de structură a manifestului la { $name }: { $details } +manifest.yaml.parse = Eroare de analiză YAML la linia { $line }, coloana { $column }: { $details } +manifest.yaml.label = YAML nevalid +manifest.yaml.hint.tabs = YAML nu permite tabulatori; folosiți spații pentru indentare. +manifest.yaml.hint.list_item = Elementele de listă YAML trebuie să înceapă cu „-” și să fie indentate corect. +manifest.yaml.hint.expected_colon = Pare o intrare de mapare; lipsește „:” după cheie. +manifest.yaml.hint.mapping_values = Mapările YAML cer o valoare după „:” (sau un bloc imbricat). +manifest.yaml.hint.invalid_token = Simbolul YAML este nevalid sau neașteptat. +manifest.yaml.hint.escape = Aplicați escape barelor oblice inverse sau eliminați secvențele de escape nevalide. +manifest.env.missing = Variabila de mediu obligatorie „{ $name }” nu este setată. +manifest.env.invalid_utf8 = Variabila de mediu „{ $name }” conține UTF-8 nevalid. +manifest.vars.not_object = Câmpul `vars` al manifestului trebuie să fie o mapare sau un obiect. +manifest.read_failed = Manifestul din { $path } nu a putut fi citit. +manifest.resolve_workspace_root = Rădăcina spațiului de lucru nu a putut fi determinată. +manifest.workspace_non_utf8 = Calea rădăcină a spațiului de lucru „{ $path }” nu este UTF-8 valid. +manifest.path_non_utf8 = Calea manifestului „{ $manifest }” nu este UTF-8 valid: { $path }. +manifest.path_missing_name = Calea manifestului „{ $path }” nu conține un nume de fișier. +manifest.open_workspace_failed = Spațiul de lucru { $workspace } nu a putut fi deschis pentru manifestul { $manifest }. +manifest.foreach.not_iterable = Expresia `foreach` nu poate fi parcursă. +manifest.foreach.serialise_item = Elementul din `foreach` nu a putut fi serializat. +manifest.when.empty = Expresia `when` nu trebuie să fie goală. +manifest.when.eval_error = Expresia `when` „{ $expr }” nu a putut fi evaluată. +manifest.when.template_error = Șablonul `when` „{ $expr }” nu a putut fi redat. +manifest.target.vars_not_object = Câmpul `vars` al țintei trebuie să fie un obiect; s-a primit { $value }. +manifest.vars.entry_not_object = O intrare `vars` a manifestului trebuie să fie un obiect. +manifest.field_not_string = Câmpul „{ $field }” trebuie să fie un șir de caractere. +manifest.expression.parse_error = Expresia { $name } nu a putut fi analizată. +manifest.expression.eval_error = Expresia { $name } nu a putut fi evaluată. + +# Diagnostice ale macrourilor din manifest. +manifest.macro.signature_missing_identifier = Din semnătura macroului lipsește un identificator. +manifest.macro.signature_missing_params = Din semnătura macroului lipsesc parametrii. +manifest.macro.compile_failed = Macroul { $name } nu a putut fi compilat. +manifest.macro.sequence_invalid = Macrourile trebuie definite ca o mapare de la nume la șabloane. +manifest.macro.register_failed = Macrourile manifestului nu au putut fi înregistrate. +manifest.macro.not_initialised = Mediul de macrouri nu este inițializat. +manifest.macro.caller_invalid = Apelantul macroului trebuie să fie un șir de caractere. +manifest.macro.template_load_failed = Șablonul macroului nu a putut fi încărcat. +manifest.macro.init_failed = Mediul de macrouri nu a putut fi inițializat. +manifest.macro.missing = Macroul { $name } lipsește. + +# Erori ale tiparelor glob din manifest. +manifest.glob.unmatched_brace = Tipar glob nevalid „{ $pattern }”: „{ $character }” fără pereche la poziția { $position }. +manifest.glob.invalid_pattern = Tipar glob nevalid „{ $pattern }”: { $detail }. +manifest.glob.unknown_pattern_error = eroare de tipar necunoscută. +manifest.glob.io_failed = Glob a eșuat pentru „{ $pattern }”: { $detail }. +manifest.glob.unknown_io_error = eroare de intrare/ieșire necunoscută. + +# Erori ale reprezentării intermediare. +ir.rule_not_found = Regula „{ $rule }” la care face referire ținta „{ $target }” nu a fost găsită. +ir.multiple_rules = Ținta „{ $target }” trebuie să facă referire la o singură regulă; s-a primit { $rules }. +ir.empty_rule = Ținta „{ $target }” trebuie să facă referire la o regulă. +ir.duplicate_outputs = Au fost detectate ieșiri duplicate: { $outputs }. +ir.circular_dependency = A fost detectată o dependență circulară: { $cycle }. +ir.action_serialisation = Acțiunea nu a putut fi serializată: { $details }. +ir.invalid_command = Interpolare nevalidă în comandă: { $snippet }. + +# Erori la generarea fișierelor Ninja. +ninja_gen.missing_action = Lipsește acțiunea „{ $id }” la care face referire o muchie de construire. +ninja_gen.format = Ieșirea manifestului Ninja nu a putut fi formatată. + +# Validarea tiparelor de gazdă. +host_pattern.empty = Tiparul de gazdă nu trebuie să fie gol. +host_pattern.contains_scheme = Tiparul de gazdă „{ $pattern }” nu trebuie să conțină o schemă URL. +host_pattern.contains_slash = Tiparul de gazdă „{ $pattern }” nu trebuie să conțină „/”. +host_pattern.missing_suffix = Tiparul de gazdă „{ $pattern }” trebuie să conțină un sufix după „*.”. +host_pattern.empty_label = Tiparul de gazdă „{ $pattern }” conține o etichetă goală. +host_pattern.invalid_chars = Tiparul de gazdă „{ $pattern }” conține caractere nevalide. +host_pattern.invalid_label_edge = Etichetele tiparului de gazdă „{ $pattern }” nu trebuie să înceapă sau să se termine cu „-”. +host_pattern.label_too_long = Tiparul de gazdă „{ $pattern }” conține o etichetă mai lungă de 63 de caractere. +host_pattern.too_long = Tiparul de gazdă „{ $pattern }” depășește limita de 255 de caractere. + +# Politica de rețea. +network_policy.scheme.empty = Schema nu trebuie să fie goală. +network_policy.scheme.invalid = Schema „{ $scheme }” conține caractere nevalide. +network_policy.allowlist.empty = Lista gazdelor permise nu trebuie să fie goală. +network_policy.scheme.not_allowed = Schema „{ $scheme }” nu este permisă. +network_policy.missing_host = Din adresa URL lipsește gazda. +network_policy.host.blocked = Gazda „{ $host }” este blocată de politică. +network_policy.host.not_allowlisted = Gazda „{ $host }” nu se află pe lista celor permise. + +# Configurarea bibliotecii standard. +stdlib.config.default_fetch_cache_invalid = Calea implicită a memoriei cache fetch trebuie să fie relativă. +stdlib.config.default_which_cache_invalid = Capacitatea implicită a memoriei cache which trebuie să fie pozitivă. +stdlib.config.workspace_root_absolute = Calea rădăcină a spațiului de lucru trebuie să fie absolută. +stdlib.config.fetch_response_limit_positive = Limita răspunsului fetch trebuie să fie pozitivă. +stdlib.config.command_output_limit_positive = Limita ieșirii capturate a comenzilor trebuie să fie pozitivă. +stdlib.config.command_stream_limit_positive = Limita fluxului comenzilor trebuie să fie pozitivă. +stdlib.config.which_cache_capacity_positive = Capacitatea memoriei cache which trebuie să fie pozitivă. +stdlib.config.skip_dir_empty = Intrările pentru directoarele omise nu trebuie să fie goale. +stdlib.config.skip_dir_navigation = Intrările pentru directoarele omise nu trebuie să conțină „..”. +stdlib.config.skip_dir_separator = Intrările pentru directoarele omise nu trebuie să conțină separatori de cale. +stdlib.config.fetch_cache_empty = Calea memoriei cache fetch nu trebuie să fie goală. +stdlib.config.fetch_cache_not_relative = Calea memoriei cache fetch trebuie să fie relativă; s-a primit { $path }. +stdlib.config.fetch_cache_escapes = Calea memoriei cache fetch nu trebuie să iasă din spațiul de lucru: { $path }. +stdlib.config.open_workspace_root = Directorul curent nu a putut fi deschis ca rădăcină a spațiului de lucru stdlib. +stdlib.config.resolve_cwd = Directorul curent nu a putut fi determinat ca rădăcină a spațiului de lucru stdlib. +stdlib.config.cwd_non_utf8 = Directorul curent conține componente care nu sunt UTF-8: { $path }. + +# Diagnostice ale ajutorului fetch. +stdlib.fetch.url_invalid = Adresă URL nevalidă „{ $url }”: { $details }. +stdlib.fetch.disallowed = Adresa URL „{ $url }” nu este permisă: { $details }. +stdlib.fetch.failed = Descărcarea de la „{ $url }” a eșuat: { $details }. +stdlib.fetch.cache_read_failed = Intrarea din memoria cache „{ $name }” nu a putut fi citită: { $details }. +stdlib.fetch.cache_open_failed = Intrarea din memoria cache „{ $name }” nu a putut fi deschisă: { $details }. +stdlib.fetch.response_read_failed = Răspunsul de la „{ $url }” nu a putut fi citit: { $details }. +stdlib.fetch.response_buffer_overflow = Depășirea memoriei tampon la citirea „{ $url }”. +stdlib.fetch.cache_write_failed = Memoria cache pentru „{ $url }” nu a putut fi scrisă: { $details }. +stdlib.fetch.response_limit_exceeded = Răspunsul de la „{ $url }” a depășit limita de { $limit } octeți. +stdlib.fetch.cache_limit_exceeded = Răspunsul din memoria cache „{ $name }” a depășit limita de { $limit } octeți. +stdlib.fetch.io_failed = Acțiunea „{ $action }” a eșuat pentru { $path }: { $details }. +stdlib.fetch.action.sync_cache = sincronizarea memoriei cache fetch +stdlib.fetch.action.create_cache_dir = crearea directorului memoriei cache fetch +stdlib.fetch.action.open_cache_dir = deschiderea directorului memoriei cache fetch +stdlib.fetch.action.stat_cache = citirea informațiilor despre intrarea din memoria cache fetch +stdlib.fetch.action.open_cache_entry = deschiderea intrării din memoria cache fetch + +# Diagnostice ale ajutorului pentru comenzi. +stdlib.command.location = comanda „{ $command }” din șablonul „{ $template }” +stdlib.command.spawn_failed = Pornirea { $location } a eșuat: { $details }. +stdlib.command.io_failed = { $location } a eșuat: { $details }. +stdlib.command.closed_input_early = Intrarea s-a închis înainte de terminarea scrierii către comandă. +stdlib.command.broken_pipe = Conductă întreruptă la rularea { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } a fost oprit de un semnal. +stdlib.command.exited_with_status = { $location } s-a încheiat cu starea { $status }. +stdlib.command.output_limit_exceeded = { $location } a depășit limita { $mode } de { $limit } octeți pentru { $stream }. +stdlib.command.timeout = { $location } a depășit limita de timp de { $seconds } secunde. +stdlib.command.exit_status_suffix = (stare de ieșire { $status }) +stdlib.command.signal_suffix = (oprit de un semnal) +stdlib.command.shell.empty = Comanda de shell nu trebuie să fie goală. +stdlib.command.grep.empty_pattern = Tiparul grep nu trebuie să fie gol. +stdlib.command.grep.flags_not_string = Fanioanele grep trebuie să fie șiruri de caractere. +stdlib.command.quote.invalid = { $arg } nu a putut fi pus între ghilimele: { $details }. +stdlib.command.quote.line_break = Argumentele care conțin retur de car sau salt de linie nu pot fi puse în siguranță între ghilimele. +stdlib.command.input_undefined = Valoarea de intrare nu este definită. +stdlib.command.tempfile.root_required = Crearea fișierelor temporare de comandă necesită rădăcina spațiului de lucru. +stdlib.command.tempfile.create_failed = Fișierul temporar al comenzii nu a putut fi creat: { $details }. +stdlib.command.options.invalid_utf8 = Cheia unei opțiuni de comandă trebuie să fie UTF-8 valid. +stdlib.command.option.mode_not_string = Modul de ieșire trebuie să fie un șir de caractere. +stdlib.command.options.invalid_type = Opțiunile comenzii trebuie să fie un obiect. +stdlib.command.output.mode_unsupported = Mod de ieșire neacceptat „{ $mode }”. +stdlib.command.output.mode.capture = captură +stdlib.command.output.mode.streaming = flux continuu +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Diagnostice ale ajutorului pentru căi. +stdlib.path.io.failed = Acțiunea „{ $action }” a eșuat pentru { $path } ({ $label }). +stdlib.path.io.failed_with_detail = Acțiunea „{ $action }” a eșuat pentru { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = Acțiunea „{ $action }” a eșuat pentru { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = negăsit +stdlib.path.io.permission_denied = acces refuzat +stdlib.path.io.already_exists = există deja +stdlib.path.io.invalid_input = intrare nevalidă +stdlib.path.io.invalid_data = date nevalide +stdlib.path.io.timed_out = timp expirat +stdlib.path.io.interrupted = întrerupt +stdlib.path.io.would_block = ar bloca execuția +stdlib.path.io.write_zero = s-au scris zero octeți +stdlib.path.io.unexpected_eof = sfârșit de fișier neașteptat +stdlib.path.io.broken_pipe = conductă întreruptă +stdlib.path.io.connection_refused = conexiune refuzată +stdlib.path.io.connection_reset = conexiune reinițializată +stdlib.path.io.connection_aborted = conexiune abandonată +stdlib.path.io.not_connected = neconectat +stdlib.path.io.addr_in_use = adresă deja folosită +stdlib.path.io.addr_not_available = adresă indisponibilă +stdlib.path.io.out_of_memory = memorie insuficientă +stdlib.path.io.unsupported = neacceptat +stdlib.path.io.file_too_large = fișier prea mare +stdlib.path.io.resource_busy = resursă ocupată +stdlib.path.io.executable_busy = executabil ocupat +stdlib.path.io.deadlock = blocaj reciproc +stdlib.path.io.crosses_devices = traversează dispozitive +stdlib.path.io.too_many_links = prea multe legături +stdlib.path.io.invalid_filename = nume de fișier nevalid +stdlib.path.io.arg_list_too_long = listă de argumente prea lungă +stdlib.path.io.stale_handle = referință de fișier de rețea învechită +stdlib.path.io.storage_full = spațiu de stocare plin +stdlib.path.io.not_seekable = nu permite poziționarea +stdlib.path.io.network_down = rețea nefuncțională +stdlib.path.io.network_unreachable = rețea inaccesibilă +stdlib.path.io.host_unreachable = gazdă inaccesibilă +stdlib.path.io.other = eroare de intrare/ieșire +stdlib.path.action.canonicalize = canonizarea +stdlib.path.action.open_directory = deschiderea directorului +stdlib.path.action.stat = citirea informațiilor +stdlib.path.action.read = citirea +stdlib.path.action.open_file = deschiderea fișierului +stdlib.path.with_suffix.empty_separator = with_suffix necesită un separator care nu este gol. +stdlib.path.relative_to.mismatch = { $path } nu este relativ la { $root }. +stdlib.path.expanduser.unsupported = Extinderea lui ~ pentru un anumit utilizator nu este acceptată. +stdlib.path.expanduser.no_home = Nu se poate extinde ~: nu este setată nicio variabilă de mediu pentru directorul personal. +stdlib.path.contents.unsupported_encoding = Codificare neacceptată „{ $encoding }”. +stdlib.path.hash.unsupported_algorithm = Algoritm de dispersie neacceptat „{ $algorithm }”. +stdlib.path.hash.unsupported_algorithm_legacy = Algoritm de dispersie neacceptat „{ $algorithm }” (activați funcționalitatea „{ $feature }”). + +# Diagnostice ale ajutoarelor pentru colecții. +stdlib.collections.flatten.expected_sequence = flatten aștepta elemente dintr-o secvență, dar a găsit { $kind }. +stdlib.collections.group_by.empty_attribute = group_by necesită un atribut care nu este gol. +stdlib.collections.group_by.unresolved = group_by nu a putut găsi „{ $attr }” pe un element de tipul { $kind }. + +# Diagnostice ale ajutoarelor pentru timp. +stdlib.time.offset.invalid = Decalajul now „{ $offset }” este nevalid: se aștepta „+HH:MM[:SS]” sau „Z”. +stdlib.time.timedelta.overflow = Depășire în timedelta la adunarea componentei { $component }. +stdlib.time.label.weeks = săptămâni +stdlib.time.label.days = zile +stdlib.time.label.hours = ore +stdlib.time.label.minutes = minute +stdlib.time.label.seconds = secunde +stdlib.time.label.milliseconds = milisecunde +stdlib.time.label.microseconds = microsecunde +stdlib.time.label.nanoseconds = nanosecunde + +# Diagnostice ale ajutorului which. +stdlib.which.not_found = [netsuke::jinja::which::not_found] comanda „{ $command }” nu a fost găsită după verificarea a { $count } intrări din PATH. Previzualizare: { $preview } +stdlib.which.not_found.hint.cwd_auto = Segmentele goale din PATH sunt ignorate; folosiți cwd_mode="auto" pentru a include directorul de lucru. +stdlib.which.not_found.hint.cwd_always = Stabiliți cwd_mode="always" pentru a include directorul curent. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] comanda „{ $command }” din „{ $path }” lipsește sau nu este executabilă. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = Intrarea nr. { $index } din PATH conține caractere care nu sunt UTF-8; Netsuke necesită căi UTF-8. +stdlib.which.command.empty = which necesită un șir de caractere care nu este gol. +stdlib.which.cwd_mode.invalid = cwd_mode trebuie să fie „auto”, „always” sau „never”; s-a primit „{ $mode }”. +stdlib.which.cwd.resolve_failed = Directorul curent nu a putut fi determinat: { $details }. +stdlib.which.cwd.non_utf8 = Directorul curent conține componente care nu sunt UTF-8. +stdlib.which.canonicalize_failed = „{ $path }” nu a putut fi canonizat: { $details }. +stdlib.which.is_executable = Nu s-a putut stabili dacă „{ $path }” este executabil: { $details }. +stdlib.which.canonicalize_non_utf8 = Calea canonică conține componente care nu sunt UTF-8. +stdlib.which.workspace_non_utf8 = Calea spațiului de lucru conține componente care nu sunt UTF-8 la rezolvarea comenzii „{ $command }”: { $path }. +stdlib.which.walkdir_error = Eroare la parcurgerea spațiului de lucru în timpul rezolvării comenzii: { $details }. + +# Înregistrarea bibliotecii standard. +stdlib.register.open_dir = Directorul curent nu a putut fi deschis pentru înregistrarea stdlib. +stdlib.register.resolve_dir = Directorul curent nu a putut fi determinat pentru înregistrarea stdlib. +stdlib.register.dir_non_utf8 = Directorul curent conține componente care nu sunt UTF-8: { $path }. + +# Raportarea stării în modul de ieșire accesibil. +status.state.pending = în așteptare +status.state.running = în desfășurare +status.state.done = finalizată +status.state.failed = eșuată +status.stage.label = Etapa { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Sarcina { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Se citește fișierul de manifest +status.stage.initial_yaml_parsing = Se analizează documentul YAML +status.stage.template_expansion = Se extind directivele șabloanelor +status.stage.final_rendering = Se deserializează și se redau valorile manifestului +status.stage.ir_generation_validation = Se construiește și se verifică graful dependențelor +status.stage.ninja_synthesis = Se sintetizează planul de construire Ninja +status.stage.ninja_synthesis_execute = Se sintetizează planul Ninja și se rulează { $tool } +status.stage.graph_rendering = Se redă artefactul grafului +status.stage.graph_rendering_with_tool = Se redă { $tool } +status.complete = { $tool }: operațiune finalizată. +status.timing.summary_header = Rezumatul timpilor pe etape: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Timpul total al fluxului: { $duration } +status.tool.build = Construire +status.tool.clean = Curățare +status.tool.graph = Graf +status.tool.graph_html = Graf (HTML) +status.tool.generate = Generare + +# Textele redării grafului în HTML. +graph.html.title = Graful de construire Netsuke +graph.html.heading = Graful de construire Netsuke +graph.html.description = Graf de construire redat de Netsuke +graph.html.outline.summary = Ținte și dependențe (schemă text) +graph.html.outline.no_inputs = Fără intrări +graph.html.noscript.notice = JavaScript este dezactivat. Schema text de mai sus conține întregul graf; mai jos urmează sursa DOT. + +# Prefixe semantice pentru ieșirea accesibilă. +semantic.prefix.error = Eroare: +semantic.prefix.warning = Avertisment: +semantic.prefix.success = Reușit: +semantic.prefix.info = Informație: +semantic.prefix.timing = Timp: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Exemple de forme de plural pentru traducători. +# Româna are trei categorii CLDR: `one`, `few` și `other`. `few` acoperă 0, +# 2–19 și resturile 101–119, precum și valorile zecimale, de exemplu 1,5; +# `other` acoperă restul numerelor întregi și cere prepoziția „de”. +example.files_processed = { $count -> + [one] S-a procesat { $count } fișier. + [few] S-au procesat { $count } fișiere. + *[other] S-au procesat { $count } de fișiere. +} + +example.errors_found = { $count -> + [0] Nu s-a găsit nicio eroare. + [one] S-a găsit { $count } eroare. + [few] S-au găsit { $count } erori. + *[other] S-au găsit { $count } de erori. +} diff --git a/locales/ru/messages.ftl b/locales/ru/messages.ftl new file mode 100644 index 000000000..a0aac8ba7 --- /dev/null +++ b/locales/ru/messages.ftl @@ -0,0 +1,404 @@ +# Ресурсы локализации командной строки Netsuke. + +cli.about = Netsuke компилирует манифесты YAML + Jinja в планы сборки Ninja. +cli.long_about = Netsuke преобразует манифесты YAML + Jinja в воспроизводимые графы Ninja и запускает Ninja с безопасными значениями по умолчанию. +cli.usage = { $usage } + +# Текст справки для общих параметров. +cli.flag.file.help = Путь к используемому файлу манифеста Netsuke. +cli.flag.directory.help = Выполнить так, как если бы запуск произошёл в этом каталоге. +cli.flag.config.help = Путь к файлу конфигурации в обход автоматического поиска. +cli.flag.jobs.help = Задать количество параллельных заданий сборки. +cli.flag.verbose.help = Включить подробное диагностическое журналирование и сводки по времени при завершении. +cli.flag.locale.help = Языковой тег для текстов командной строки (например: en-US, ru). +cli.flag.fetch_allow_scheme.help = Дополнительные схемы URL, разрешённые для помощника fetch. +cli.flag.fetch_allow_host.help = Имена узлов, разрешённые при включённом запрете по умолчанию. +cli.flag.fetch_block_host.help = Имена узлов, которые блокируются всегда, даже если разрешены в другом месте. +cli.flag.fetch_default_deny.help = Запрещать все узлы по умолчанию; разрешать только объявленный список. +cli.flag.json.help = Выводить машиночитаемый JSON. +cli.flag.no_input.help = Никогда не читать интерактивный ввод. +cli.flag.color.help = Политика цветного вывода (auto, always, never). +cli.flag.emoji.help = Политика использования эмодзи (auto, always, never). +cli.flag.progress.help = Политика отображения хода выполнения (auto, always, never). +cli.flag.accessibility.help = Политика доступного вывода (auto, on, off). +cli.flag.default_targets.help = Цели сборки по умолчанию, когда ни одна не указана. + +# Описания подкоманд. +cli.subcommand.build.about = Собрать цели, объявленные в манифесте (по умолчанию). +cli.subcommand.build.long_about = Собрать запрошенные цели; если ни одна не указана, использовать цели манифеста по умолчанию. +cli.subcommand.clean.about = Удалить артефакты сборки средствами Ninja. +cli.subcommand.clean.long_about = Создать временный файл Ninja, затем выполнить `ninja -t clean`. +cli.subcommand.graph.about = Вывести граф зависимостей сборки. Формат по умолчанию — DOT. +cli.subcommand.graph.long_about = Преобразовать разобранный манифест Netsuke в канонический граф сборки и записать его в формате Graphviz DOT либо, с параметром `--html`, как самостоятельную HTML-страницу. Используйте `--output <ФАЙЛ>` для записи в файл; `-` выводит в стандартный поток. +cli.subcommand.generate.about = Создать манифест Ninja, не запуская Ninja. +cli.subcommand.generate.long_about = Записать созданный манифест Ninja в стандартный поток вывода либо в файл, выбранный параметром `--output`. + +# Текст справки для параметров подкоманды build. +cli.subcommand.build.flag.targets.help = Цели для сборки (если не указаны, берутся цели манифеста по умолчанию). + +# Текст справки для параметров подкоманды graph. +cli.subcommand.graph.flag.html.help = Отобразить граф как самостоятельную HTML-страницу вместо формата DOT. +cli.subcommand.graph.flag.output.help = Записать артефакт графа в ФАЙЛ; используйте `-` для стандартного потока вывода. + +# Текст справки для параметров подкоманды generate. +cli.subcommand.generate.flag.output.help = Записать созданный манифест Ninja в ФАЙЛ вместо стандартного потока вывода. + +# Ошибки проверки в командной строке. +cli.validation.jobs.invalid_number = { $value } не является допустимым числом. +cli.validation.jobs.out_of_range = Количество заданий должно быть в диапазоне от { $min } до { $max }. +cli.validation.scheme.empty = Схема не должна быть пустой. +cli.validation.scheme.invalid_start = Схема «{ $scheme }» должна начинаться с буквы ASCII. +cli.validation.scheme.invalid = Недопустимая схема «{ $scheme }». +cli.validation.locale.empty = Языковой тег не должен быть пустым. +cli.validation.locale.invalid = Недопустимый языковой тег «{ $locale }». +cli.validation.color.invalid = Недопустимая политика цвета «{ $value }». Допустимые значения: auto, always, never. +cli.validation.emoji.invalid = Недопустимая политика эмодзи «{ $value }». Допустимые значения: auto, always, never. +cli.validation.progress.invalid = Недопустимая политика хода выполнения «{ $value }». Допустимые значения: auto, always, never. +cli.validation.accessibility.invalid = Недопустимая политика доступности «{ $value }». Допустимые значения: auto, on, off. +cli.validation.config.expected_object = Значения командной строки должны были сериализоваться в объект, получено { $value }. + +# Сообщения об ошибках Clap. +clap-error-missing-argument = Отсутствует обязательный аргумент: { $argument } +clap-error-missing-subcommand = Отсутствует подкоманда. Доступные варианты: { $valid_subcommands } +clap-error-unknown-argument = Неизвестный аргумент: { $argument } +clap-error-invalid-value = Недопустимое значение для { $argument }: { $value } +clap-error-invalid-subcommand = Неизвестная подкоманда: { $subcommand } +# Примечание: формулировка value-validation отличается от invalid-value, чтобы +# различать ошибки собственных проверяющих (ErrorKind::ValueValidation) и +# несовпадение типов (ErrorKind::InvalidValue). +clap-error-value-validation = Проверка не пройдена для { $argument }: { $value } + +# Ошибки и контекст выполнения. +runner.manifest.not_found = Манифест «{ $manifest_name }» не найден в каталоге { $directory }. +runner.manifest.not_found.help = Убедитесь, что манифест существует, либо укажите `--file` с правильным путём. +runner.manifest.path_missing_name = В пути к манифесту «{ $path }» нет имени файла. +runner.manifest.path_utf8 = Путь к манифесту «{ $path }» не является корректным UTF-8. +runner.manifest.directory_utf8 = Путь к каталогу манифеста «{ $path }» не является корректным UTF-8. +runner.manifest.directory_label = каталог `{ $directory }` +runner.manifest.current_directory_label = текущий каталог +runner.context.network_policy = Не удалось построить сетевую политику. +runner.context.load_manifest = Не удалось загрузить манифест по пути { $path }. +runner.context.serialise_manifest = Не удалось сериализовать манифест. +runner.context.build_graph = Не удалось построить граф по манифесту. +runner.context.generate_ninja = Не удалось создать манифест Ninja. +runner.context.render_graph = Не удалось отобразить артефакт графа. + +runner.io.create_temp_file = Не удалось создать временный файл Ninja. +runner.io.write_temp_ninja = Не удалось записать временный файл Ninja. +runner.io.flush_temp_ninja = Не удалось сбросить буфер временного файла Ninja. +runner.io.sync_temp_ninja = Не удалось синхронизировать временный файл Ninja. +runner.io.create_parent_dir = Не удалось создать родительский каталог { $path }. +runner.io.create_ninja_file = Не удалось создать файл Ninja в { $path }. +runner.io.write_ninja_file = Не удалось записать файл Ninja в { $path }. +runner.io.flush_ninja_file = Не удалось сбросить буфер файла Ninja в { $path }. +runner.io.sync_ninja_file = Не удалось синхронизировать файл Ninja в { $path }. +runner.io.open_ambient_dir = Не удалось открыть окружающий каталог. +runner.io.no_existing_ancestor = Для { $path } не существует родительского каталога. +runner.io.derive_relative_path = Не удалось вывести относительный путь Ninja. +runner.io.non_utf8_path = Пути, отличные от UTF-8, не поддерживаются (путь: { $path }). +runner.io.write_stdout = Не удалось записать манифест Ninja в стандартный поток вывода. +runner.io.flush_stdout = Не удалось сбросить буфер стандартного потока вывода. + +# Диагностика манифеста. +manifest.parse = Не удалось разобрать манифест. +manifest.structure_error = Ошибка структуры манифеста в { $name }: { $details } +manifest.yaml.parse = Ошибка разбора YAML в строке { $line }, столбце { $column }: { $details } +manifest.yaml.label = некорректный YAML +manifest.yaml.hint.tabs = YAML не допускает табуляции; используйте для отступов пробелы. +manifest.yaml.hint.list_item = Элементы списка YAML должны начинаться с «-» и иметь правильный отступ. +manifest.yaml.hint.expected_colon = Похоже на элемент отображения; после ключа не хватает «:». +manifest.yaml.hint.mapping_values = Отображения YAML требуют значение после «:» (либо вложенный блок). +manifest.yaml.hint.invalid_token = Лексема YAML некорректна или неожиданна. +manifest.yaml.hint.escape = Экранируйте обратные косые черты либо удалите некорректные escape-последовательности. +manifest.env.missing = Обязательная переменная окружения «{ $name }» не задана. +manifest.env.invalid_utf8 = Переменная окружения «{ $name }» содержит некорректный UTF-8. +manifest.vars.not_object = Поле `vars` манифеста должно быть отображением или объектом. +manifest.read_failed = Не удалось прочитать манифест по пути { $path }. +manifest.resolve_workspace_root = Не удалось определить корень рабочего пространства. +manifest.workspace_non_utf8 = Корневой путь рабочего пространства «{ $path }» не является корректным UTF-8. +manifest.path_non_utf8 = Путь манифеста «{ $manifest }» не является корректным UTF-8: { $path }. +manifest.path_missing_name = В пути к манифесту «{ $path }» нет имени файла. +manifest.open_workspace_failed = Не удалось открыть рабочее пространство { $workspace } для манифеста { $manifest }. +manifest.foreach.not_iterable = Выражение `foreach` не является перебираемым. +manifest.foreach.serialise_item = Не удалось сериализовать элемент `foreach`. +manifest.when.empty = Выражение `when` не должно быть пустым. +manifest.when.eval_error = Не удалось вычислить выражение `when` «{ $expr }». +manifest.when.template_error = Не удалось отобразить шаблон `when` «{ $expr }». +manifest.target.vars_not_object = Поле `vars` цели должно быть объектом, получено { $value }. +manifest.vars.entry_not_object = Запись `vars` манифеста должна быть объектом. +manifest.field_not_string = Поле «{ $field }» должно быть строкой. +manifest.expression.parse_error = Не удалось разобрать выражение { $name }. +manifest.expression.eval_error = Не удалось вычислить выражение { $name }. + +# Диагностика макросов манифеста. +manifest.macro.signature_missing_identifier = В сигнатуре макроса отсутствует идентификатор. +manifest.macro.signature_missing_params = В сигнатуре макроса отсутствуют параметры. +manifest.macro.compile_failed = Не удалось скомпилировать макрос { $name }. +manifest.macro.sequence_invalid = Макросы должны задаваться как отображение имён на шаблоны. +manifest.macro.register_failed = Не удалось зарегистрировать макросы манифеста. +manifest.macro.not_initialised = Окружение макросов не инициализировано. +manifest.macro.caller_invalid = Вызывающий макрос должен быть строкой. +manifest.macro.template_load_failed = Не удалось загрузить шаблон макроса. +manifest.macro.init_failed = Не удалось инициализировать окружение макросов. +manifest.macro.missing = Макрос { $name } отсутствует. + +# Ошибки шаблонов glob в манифесте. +manifest.glob.unmatched_brace = Некорректный шаблон glob «{ $pattern }»: «{ $character }» без пары в позиции { $position }. +manifest.glob.invalid_pattern = Некорректный шаблон glob «{ $pattern }»: { $detail }. +manifest.glob.unknown_pattern_error = неизвестная ошибка шаблона. +manifest.glob.io_failed = Сбой glob для «{ $pattern }»: { $detail }. +manifest.glob.unknown_io_error = неизвестная ошибка ввода-вывода. + +# Ошибки промежуточного представления. +ir.rule_not_found = Правило «{ $rule }», на которое ссылается цель «{ $target }», не найдено. +ir.multiple_rules = Цель «{ $target }» должна ссылаться ровно на одно правило, получено { $rules }. +ir.empty_rule = Цель «{ $target }» должна ссылаться на правило. +ir.duplicate_outputs = Обнаружены повторяющиеся выходные файлы: { $outputs }. +ir.circular_dependency = Обнаружена циклическая зависимость: { $cycle }. +ir.action_serialisation = Не удалось сериализовать действие: { $details }. +ir.invalid_command = Некорректная подстановка в команде: { $snippet }. + +# Ошибки генерации файлов Ninja. +ninja_gen.missing_action = Отсутствует действие «{ $id }», на которое ссылается ребро сборки. +ninja_gen.format = Не удалось отформатировать вывод манифеста Ninja. + +# Проверка шаблонов узлов. +host_pattern.empty = Шаблон узла не должен быть пустым. +host_pattern.contains_scheme = Шаблон узла «{ $pattern }» не должен содержать схему URL. +host_pattern.contains_slash = Шаблон узла «{ $pattern }» не должен содержать «/». +host_pattern.missing_suffix = Шаблон узла «{ $pattern }» должен содержать суффикс после «*.». +host_pattern.empty_label = Шаблон узла «{ $pattern }» содержит пустую метку. +host_pattern.invalid_chars = Шаблон узла «{ $pattern }» содержит недопустимые символы. +host_pattern.invalid_label_edge = Метки шаблона узла «{ $pattern }» не должны начинаться или заканчиваться символом «-». +host_pattern.label_too_long = Шаблон узла «{ $pattern }» содержит метку длиннее 63 символов. +host_pattern.too_long = Шаблон узла «{ $pattern }» превышает ограничение в 255 символов. + +# Сетевая политика. +network_policy.scheme.empty = Схема не должна быть пустой. +network_policy.scheme.invalid = Схема «{ $scheme }» содержит недопустимые символы. +network_policy.allowlist.empty = Список разрешённых узлов не должен быть пустым. +network_policy.scheme.not_allowed = Схема «{ $scheme }» не разрешена. +network_policy.missing_host = В URL отсутствует узел. +network_policy.host.blocked = Узел «{ $host }» заблокирован политикой. +network_policy.host.not_allowlisted = Узла «{ $host }» нет в списке разрешённых. + +# Конфигурация стандартной библиотеки. +stdlib.config.default_fetch_cache_invalid = Путь кэша fetch по умолчанию должен быть относительным. +stdlib.config.default_which_cache_invalid = Ёмкость кэша which по умолчанию должна быть положительной. +stdlib.config.workspace_root_absolute = Корневой путь рабочего пространства должен быть абсолютным. +stdlib.config.fetch_response_limit_positive = Ограничение на ответ fetch должно быть положительным. +stdlib.config.command_output_limit_positive = Ограничение на перехватываемый вывод команд должно быть положительным. +stdlib.config.command_stream_limit_positive = Ограничение на поток команд должно быть положительным. +stdlib.config.which_cache_capacity_positive = Ёмкость кэша which должна быть положительной. +stdlib.config.skip_dir_empty = Записи пропускаемых каталогов не должны быть пустыми. +stdlib.config.skip_dir_navigation = Записи пропускаемых каталогов не должны содержать «..». +stdlib.config.skip_dir_separator = Записи пропускаемых каталогов не должны содержать разделители пути. +stdlib.config.fetch_cache_empty = Путь кэша fetch не должен быть пустым. +stdlib.config.fetch_cache_not_relative = Путь кэша fetch должен быть относительным, получено { $path }. +stdlib.config.fetch_cache_escapes = Путь кэша fetch не должен выходить за пределы рабочего пространства: { $path }. +stdlib.config.open_workspace_root = Не удалось открыть текущий каталог как корень рабочего пространства stdlib. +stdlib.config.resolve_cwd = Не удалось определить текущий каталог как корень рабочего пространства stdlib. +stdlib.config.cwd_non_utf8 = Текущий каталог содержит части, не являющиеся UTF-8: { $path }. + +# Диагностика помощника fetch. +stdlib.fetch.url_invalid = Некорректный URL «{ $url }»: { $details }. +stdlib.fetch.disallowed = URL «{ $url }» не разрешён: { $details }. +stdlib.fetch.failed = Не удалось загрузить «{ $url }»: { $details }. +stdlib.fetch.cache_read_failed = Не удалось прочитать запись кэша «{ $name }»: { $details }. +stdlib.fetch.cache_open_failed = Не удалось открыть запись кэша «{ $name }»: { $details }. +stdlib.fetch.response_read_failed = Не удалось прочитать ответ от «{ $url }»: { $details }. +stdlib.fetch.response_buffer_overflow = Переполнение буфера при чтении «{ $url }». +stdlib.fetch.cache_write_failed = Не удалось записать кэш для «{ $url }»: { $details }. +stdlib.fetch.response_limit_exceeded = Ответ от «{ $url }» превысил ограничение в { $limit } байт. +stdlib.fetch.cache_limit_exceeded = Кэшированный ответ «{ $name }» превысил ограничение в { $limit } байт. +stdlib.fetch.io_failed = Не удалось выполнить действие «{ $action }» для { $path }: { $details }. +stdlib.fetch.action.sync_cache = синхронизация кэша fetch +stdlib.fetch.action.create_cache_dir = создание каталога кэша fetch +stdlib.fetch.action.open_cache_dir = открытие каталога кэша fetch +stdlib.fetch.action.stat_cache = получение сведений о записи кэша fetch +stdlib.fetch.action.open_cache_entry = открытие записи кэша fetch + +# Диагностика помощника для команд. +stdlib.command.location = команда «{ $command }» в шаблоне «{ $template }» +stdlib.command.spawn_failed = Не удалось запустить { $location }: { $details }. +stdlib.command.io_failed = Сбой { $location }: { $details }. +stdlib.command.closed_input_early = Ввод закрылся до завершения записи в команду. +stdlib.command.broken_pipe = Разорванный канал при выполнении { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } завершена сигналом. +stdlib.command.exited_with_status = { $location } завершилась с кодом { $status }. +stdlib.command.output_limit_exceeded = { $location } превысила ограничение режима «{ $mode }» в { $limit } байт для { $stream }. +stdlib.command.timeout = { $location } превысила предельное время в { $seconds } с. +stdlib.command.exit_status_suffix = (код завершения { $status }) +stdlib.command.signal_suffix = (завершено сигналом) +stdlib.command.shell.empty = Команда оболочки не должна быть пустой. +stdlib.command.grep.empty_pattern = Шаблон grep не должен быть пустым. +stdlib.command.grep.flags_not_string = Флаги grep должны быть строками. +stdlib.command.quote.invalid = Не удалось заключить { $arg } в кавычки: { $details }. +stdlib.command.quote.line_break = Аргументы с возвратом каретки или переводом строки нельзя безопасно заключить в кавычки. +stdlib.command.input_undefined = Входное значение не определено. +stdlib.command.tempfile.root_required = Для создания временных файлов команд требуется корень рабочего пространства. +stdlib.command.tempfile.create_failed = Не удалось создать временный файл команды: { $details }. +stdlib.command.options.invalid_utf8 = Ключ параметра команды должен быть корректным UTF-8. +stdlib.command.option.mode_not_string = Режим вывода должен быть строкой. +stdlib.command.options.invalid_type = Параметры команды должны быть объектом. +stdlib.command.output.mode_unsupported = Неподдерживаемый режим вывода «{ $mode }». +stdlib.command.output.mode.capture = перехват +stdlib.command.output.mode.streaming = потоковая передача +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Диагностика помощника для путей. +stdlib.path.io.failed = Не удалось выполнить действие «{ $action }» для { $path } ({ $label }). +stdlib.path.io.failed_with_detail = Не удалось выполнить действие «{ $action }» для { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = Не удалось выполнить действие «{ $action }» для { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = не найдено +stdlib.path.io.permission_denied = доступ запрещён +stdlib.path.io.already_exists = уже существует +stdlib.path.io.invalid_input = некорректный ввод +stdlib.path.io.invalid_data = некорректные данные +stdlib.path.io.timed_out = истекло время ожидания +stdlib.path.io.interrupted = прервано +stdlib.path.io.would_block = привело бы к блокировке +stdlib.path.io.write_zero = записано ноль байт +stdlib.path.io.unexpected_eof = неожиданный конец файла +stdlib.path.io.broken_pipe = разорванный канал +stdlib.path.io.connection_refused = в соединении отказано +stdlib.path.io.connection_reset = соединение сброшено +stdlib.path.io.connection_aborted = соединение прервано +stdlib.path.io.not_connected = нет соединения +stdlib.path.io.addr_in_use = адрес уже используется +stdlib.path.io.addr_not_available = адрес недоступен +stdlib.path.io.out_of_memory = недостаточно памяти +stdlib.path.io.unsupported = не поддерживается +stdlib.path.io.file_too_large = файл слишком велик +stdlib.path.io.resource_busy = ресурс занят +stdlib.path.io.executable_busy = исполняемый файл занят +stdlib.path.io.deadlock = взаимная блокировка +stdlib.path.io.crosses_devices = пересекает границу устройств +stdlib.path.io.too_many_links = слишком много ссылок +stdlib.path.io.invalid_filename = некорректное имя файла +stdlib.path.io.arg_list_too_long = слишком длинный список аргументов +stdlib.path.io.stale_handle = устаревший дескриптор сетевого файла +stdlib.path.io.storage_full = хранилище заполнено +stdlib.path.io.not_seekable = позиционирование недоступно +stdlib.path.io.network_down = сеть не работает +stdlib.path.io.network_unreachable = сеть недоступна +stdlib.path.io.host_unreachable = узел недоступен +stdlib.path.io.other = ошибка ввода-вывода +stdlib.path.action.canonicalize = канонизация +stdlib.path.action.open_directory = открытие каталога +stdlib.path.action.stat = получение сведений +stdlib.path.action.read = чтение +stdlib.path.action.open_file = открытие файла +stdlib.path.with_suffix.empty_separator = with_suffix требует непустой разделитель. +stdlib.path.relative_to.mismatch = { $path } не является относительным к { $root }. +stdlib.path.expanduser.unsupported = Раскрытие ~ для конкретного пользователя не поддерживается. +stdlib.path.expanduser.no_home = Не удаётся раскрыть ~: не задана ни одна переменная окружения домашнего каталога. +stdlib.path.contents.unsupported_encoding = Неподдерживаемая кодировка «{ $encoding }». +stdlib.path.hash.unsupported_algorithm = Неподдерживаемый алгоритм хеширования «{ $algorithm }». +stdlib.path.hash.unsupported_algorithm_legacy = Неподдерживаемый алгоритм хеширования «{ $algorithm }» (включите возможность «{ $feature }»). + +# Диагностика помощников для коллекций. +stdlib.collections.flatten.expected_sequence = flatten ожидал элементы последовательности, но обнаружил { $kind }. +stdlib.collections.group_by.empty_attribute = group_by требует непустой атрибут. +stdlib.collections.group_by.unresolved = group_by не смог найти «{ $attr }» у элемента типа { $kind }. + +# Диагностика помощников для времени. +stdlib.time.offset.invalid = Смещение now «{ $offset }» некорректно: ожидалось «+HH:MM[:SS]» или «Z». +stdlib.time.timedelta.overflow = Переполнение timedelta при добавлении компонента { $component }. +stdlib.time.label.weeks = недели +stdlib.time.label.days = дни +stdlib.time.label.hours = часы +stdlib.time.label.minutes = минуты +stdlib.time.label.seconds = секунды +stdlib.time.label.milliseconds = миллисекунды +stdlib.time.label.microseconds = микросекунды +stdlib.time.label.nanoseconds = наносекунды + +# Диагностика помощника which. +stdlib.which.not_found = [netsuke::jinja::which::not_found] команда «{ $command }» не найдена после проверки { $count } записей PATH. Предпросмотр: { $preview } +stdlib.which.not_found.hint.cwd_auto = Пустые сегменты PATH игнорируются; задайте cwd_mode="auto", чтобы включить рабочий каталог. +stdlib.which.not_found.hint.cwd_always = Задайте cwd_mode="always", чтобы включить текущий каталог. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] команда «{ $command }» по пути «{ $path }» отсутствует или не является исполняемой. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = <пусто> +stdlib.which.path_entry.non_utf8 = Запись PATH № { $index } содержит символы, не являющиеся UTF-8; Netsuke требует пути в UTF-8. +stdlib.which.command.empty = which требует непустую строку. +stdlib.which.cwd_mode.invalid = cwd_mode должен быть «auto», «always» или «never», получено «{ $mode }». +stdlib.which.cwd.resolve_failed = Не удалось определить текущий каталог: { $details }. +stdlib.which.cwd.non_utf8 = Текущий каталог содержит части, не являющиеся UTF-8. +stdlib.which.canonicalize_failed = Не удалось канонизировать «{ $path }»: { $details }. +stdlib.which.is_executable = Не удалось проверить, является ли «{ $path }» исполняемым: { $details }. +stdlib.which.canonicalize_non_utf8 = Канонический путь содержит части, не являющиеся UTF-8. +stdlib.which.workspace_non_utf8 = Путь рабочего пространства содержит части, не являющиеся UTF-8, при поиске команды «{ $command }»: { $path }. +stdlib.which.walkdir_error = Ошибка обхода рабочего пространства при поиске команды: { $details }. + +# Регистрация стандартной библиотеки. +stdlib.register.open_dir = Не удалось открыть текущий каталог для регистрации stdlib. +stdlib.register.resolve_dir = Не удалось определить текущий каталог для регистрации stdlib. +stdlib.register.dir_non_utf8 = Текущий каталог содержит части, не являющиеся UTF-8: { $path }. + +# Отчёт о состоянии в доступном режиме вывода. +status.state.pending = ожидает +status.state.running = выполняется +status.state.done = готово +status.state.failed = сбой +status.stage.label = Этап { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Задача { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Чтение файла манифеста +status.stage.initial_yaml_parsing = Разбор документа YAML +status.stage.template_expansion = Раскрытие директив шаблона +status.stage.final_rendering = Десериализация и отображение значений манифеста +status.stage.ir_generation_validation = Построение и проверка графа зависимостей +status.stage.ninja_synthesis = Построение плана сборки Ninja +status.stage.ninja_synthesis_execute = Построение плана Ninja и запуск { $tool } +status.stage.graph_rendering = Отображение артефакта графа +status.stage.graph_rendering_with_tool = Отображение { $tool } +status.complete = { $tool }: операция завершена. +status.timing.summary_header = Сводка времени по этапам: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Общее время конвейера: { $duration } +status.tool.build = Сборка +status.tool.clean = Очистка +status.tool.graph = Граф +status.tool.graph_html = Граф (HTML) +status.tool.generate = Генерация + +# Строки HTML-представления графа. +graph.html.title = Граф сборки Netsuke +graph.html.heading = Граф сборки Netsuke +graph.html.description = Граф сборки, отображённый Netsuke +graph.html.outline.summary = Цели и зависимости (текстовая структура) +graph.html.outline.no_inputs = Нет входных данных +graph.html.noscript.notice = JavaScript отключён. Текстовая структура выше содержит весь граф; ниже приведён исходный код DOT. + +# Семантические префиксы доступного вывода. +semantic.prefix.error = Ошибка: +semantic.prefix.warning = Предупреждение: +semantic.prefix.success = Успешно: +semantic.prefix.info = Сведения: +semantic.prefix.timing = Время: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Примеры форм множественного числа для переводчиков. +# Русский использует категории CLDR `one`, `few`, `many` и `other`. Целые +# числа распределяются так: `one` — 1, 21, 31…, `few` — 2–4, 22–24…, +# `many` — 0, 5–20, 25–30… Категория `other` относится к дробным значениям, +# поэтому она же служит вариантом по умолчанию. +example.files_processed = { $count -> + [one] Обработан { $count } файл. + [few] Обработано { $count } файла. + [many] Обработано { $count } файлов. + *[other] Обработано { $count } файла. +} + +example.errors_found = { $count -> + [0] Ошибок не найдено. + [one] Найдена { $count } ошибка. + [few] Найдено { $count } ошибки. + [many] Найдено { $count } ошибок. + *[other] Найдено { $count } ошибки. +} diff --git a/locales/sv/messages.ftl b/locales/sv/messages.ftl new file mode 100644 index 000000000..7b4eb46d7 --- /dev/null +++ b/locales/sv/messages.ftl @@ -0,0 +1,397 @@ +# Lokaliseringsresurser för Netsukes kommandoradsgränssnitt. + +cli.about = Netsuke kompilerar YAML- + Jinja-manifest till Ninja-byggplaner. +cli.long_about = Netsuke omvandlar YAML- + Jinja-manifest till reproducerbara Ninja-grafer och kör Ninja med säkra standardvärden. +cli.usage = { $usage } + +# Hjälptext för globala flaggor. +cli.flag.file.help = Sökväg till den Netsuke-manifestfil som ska användas. +cli.flag.directory.help = Kör som om starten hade skett i den här katalogen. +cli.flag.config.help = Sökväg till en konfigurationsfil, förbi den automatiska sökningen. +cli.flag.jobs.help = Ange antalet parallella byggjobb. +cli.flag.verbose.help = Aktivera utförlig diagnostikloggning och tidssammanfattningar vid avslut. +cli.flag.locale.help = Språktagg för kommandoradens texter (till exempel: en-US, sv). +cli.flag.fetch_allow_scheme.help = Ytterligare URL-scheman som hjälpfunktionen fetch får använda. +cli.flag.fetch_allow_host.help = Värdnamn som tillåts när standardnekandet är aktivt. +cli.flag.fetch_block_host.help = Värdnamn som alltid blockeras, även om de tillåts på annat håll. +cli.flag.fetch_default_deny.help = Neka alla värdar som standard; tillåt endast den angivna listan. +cli.flag.json.help = Skriv ut maskinläsbar JSON. +cli.flag.no_input.help = Läs aldrig interaktiv indata. +cli.flag.color.help = Policy för färgad utdata (auto, always, never). +cli.flag.emoji.help = Policy för emoji (auto, always, never). +cli.flag.progress.help = Policy för förloppsvisning (auto, always, never). +cli.flag.accessibility.help = Policy för tillgänglig utdata (auto, on, off). +cli.flag.default_targets.help = Standardmål för bygget när inga anges. + +# Beskrivningar av underkommandon. +cli.subcommand.build.about = Bygg de mål som definierats i manifestet (standard). +cli.subcommand.build.long_about = Bygg de begärda målen; om inga anges används manifestets standardmål. +cli.subcommand.clean.about = Ta bort byggartefakter via Ninja. +cli.subcommand.clean.long_about = Skapa en tillfällig Ninja-fil och kör sedan `ninja -t clean`. +cli.subcommand.graph.about = Skriv ut byggets beroendegraf. Standardformatet är DOT. +cli.subcommand.graph.long_about = Projicera det tolkade Netsuke-manifestet till en kanonisk bygggraf och skriv den som Graphviz DOT, eller som en fristående HTML-sida med `--html`. Använd `--output ` för att skriva till en fil; `-` skriver till stdout. +cli.subcommand.generate.about = Skapa Ninja-manifestet utan att köra Ninja. +cli.subcommand.generate.long_about = Skriv det skapade Ninja-manifestet till stdout eller till en fil som väljs med `--output`. + +# Hjälptext för flaggor till underkommandot build. +cli.subcommand.build.flag.targets.help = Mål som ska byggas (använder manifestets standardmål om det utelämnas). + +# Hjälptext för flaggor till underkommandot graph. +cli.subcommand.graph.flag.html.help = Rendera grafen som en fristående HTML-sida i stället för DOT. +cli.subcommand.graph.flag.output.help = Skriv grafartefakten till FIL; använd `-` för stdout. + +# Hjälptext för flaggor till underkommandot generate. +cli.subcommand.generate.flag.output.help = Skriv det skapade Ninja-manifestet till FIL i stället för stdout. + +# Valideringsfel i kommandoradsgränssnittet. +cli.validation.jobs.invalid_number = { $value } är inte ett giltigt tal. +cli.validation.jobs.out_of_range = Antalet jobb måste ligga mellan { $min } och { $max }. +cli.validation.scheme.empty = Schemat får inte vara tomt. +cli.validation.scheme.invalid_start = Schemat ”{ $scheme }” måste börja med en ASCII-bokstav. +cli.validation.scheme.invalid = Ogiltigt schema ”{ $scheme }”. +cli.validation.locale.empty = Språktaggen får inte vara tom. +cli.validation.locale.invalid = Ogiltig språktagg ”{ $locale }”. +cli.validation.color.invalid = Ogiltig färgpolicy ”{ $value }”. Giltiga val: auto, always, never. +cli.validation.emoji.invalid = Ogiltig emojipolicy ”{ $value }”. Giltiga val: auto, always, never. +cli.validation.progress.invalid = Ogiltig förloppspolicy ”{ $value }”. Giltiga val: auto, always, never. +cli.validation.accessibility.invalid = Ogiltig tillgänglighetspolicy ”{ $value }”. Giltiga val: auto, on, off. +cli.validation.config.expected_object = Kommandoradens värden skulle serialiseras till ett objekt, men gav { $value }. + +# Felmeddelanden från Clap. +clap-error-missing-argument = Obligatoriskt argument saknas: { $argument } +clap-error-missing-subcommand = Underkommando saknas. Tillgängliga val: { $valid_subcommands } +clap-error-unknown-argument = Okänt argument: { $argument } +clap-error-invalid-value = Ogiltigt värde för { $argument }: { $value } +clap-error-invalid-subcommand = Okänt underkommando: { $subcommand } +# Obs: value-validation är formulerat annorlunda än invalid-value för att +# skilja fel från egna validerare (ErrorKind::ValueValidation) från +# typkonflikter (ErrorKind::InvalidValue). +clap-error-value-validation = Valideringen misslyckades för { $argument }: { $value } + +# Fel och sammanhang från körningen. +runner.manifest.not_found = Manifestet ”{ $manifest_name }” hittades inte i { $directory }. +runner.manifest.not_found.help = Kontrollera att manifestet finns, eller ange `--file` med rätt sökväg. +runner.manifest.path_missing_name = Manifestsökvägen ”{ $path }” saknar filnamn. +runner.manifest.path_utf8 = Manifestsökvägen ”{ $path }” är inte giltig UTF-8. +runner.manifest.directory_utf8 = Sökvägen till manifestkatalogen ”{ $path }” är inte giltig UTF-8. +runner.manifest.directory_label = katalogen `{ $directory }` +runner.manifest.current_directory_label = den aktuella katalogen +runner.context.network_policy = Nätverkspolicyn kunde inte byggas. +runner.context.load_manifest = Manifestet i { $path } kunde inte läsas in. +runner.context.serialise_manifest = Manifestet kunde inte serialiseras. +runner.context.build_graph = Grafen kunde inte byggas utifrån manifestet. +runner.context.generate_ninja = Ninja-manifestet kunde inte skapas. +runner.context.render_graph = Grafartefakten kunde inte renderas. + +runner.io.create_temp_file = Den tillfälliga Ninja-filen kunde inte skapas. +runner.io.write_temp_ninja = Den tillfälliga Ninja-filen kunde inte skrivas. +runner.io.flush_temp_ninja = Bufferten för den tillfälliga Ninja-filen kunde inte tömmas. +runner.io.sync_temp_ninja = Den tillfälliga Ninja-filen kunde inte synkroniseras. +runner.io.create_parent_dir = Överkatalogen { $path } kunde inte skapas. +runner.io.create_ninja_file = Ninja-filen i { $path } kunde inte skapas. +runner.io.write_ninja_file = Ninja-filen i { $path } kunde inte skrivas. +runner.io.flush_ninja_file = Bufferten för Ninja-filen i { $path } kunde inte tömmas. +runner.io.sync_ninja_file = Ninja-filen i { $path } kunde inte synkroniseras. +runner.io.open_ambient_dir = Den omgivande katalogen kunde inte öppnas. +runner.io.no_existing_ancestor = Det finns ingen överordnad katalog för { $path }. +runner.io.derive_relative_path = Den relativa Ninja-sökvägen kunde inte härledas. +runner.io.non_utf8_path = Sökvägar som inte är UTF-8 stöds inte (sökväg: { $path }). +runner.io.write_stdout = Ninja-manifestet kunde inte skrivas till stdout. +runner.io.flush_stdout = Bufferten för stdout kunde inte tömmas. + +# Manifestdiagnostik. +manifest.parse = Tolkningen av manifestet misslyckades. +manifest.structure_error = Strukturfel i manifestet vid { $name }: { $details } +manifest.yaml.parse = YAML-fel på rad { $line }, kolumn { $column }: { $details } +manifest.yaml.label = ogiltig YAML +manifest.yaml.hint.tabs = YAML tillåter inte tabbtecken; använd blanksteg för indrag. +manifest.yaml.hint.list_item = YAML-listposter måste börja med ”-” och vara korrekt indragna. +manifest.yaml.hint.expected_colon = Det här ser ut som en post i en mappning; det saknas ett ”:” efter nyckeln. +manifest.yaml.hint.mapping_values = YAML-mappningar kräver ett värde efter ”:” (eller ett indraget block). +manifest.yaml.hint.invalid_token = YAML-symbolen är ogiltig eller oväntad. +manifest.yaml.hint.escape = Escapa omvända snedstreck eller ta bort ogiltiga escapesekvenser. +manifest.env.missing = Den obligatoriska miljövariabeln ”{ $name }” är inte satt. +manifest.env.invalid_utf8 = Miljövariabeln ”{ $name }” innehåller ogiltig UTF-8. +manifest.vars.not_object = Manifestets `vars` måste vara en mappning eller ett objekt. +manifest.read_failed = Manifestet i { $path } kunde inte läsas. +manifest.resolve_workspace_root = Arbetsytans rot kunde inte fastställas. +manifest.workspace_non_utf8 = Arbetsytans rotsökväg ”{ $path }” är inte giltig UTF-8. +manifest.path_non_utf8 = Sökvägen till manifestet ”{ $manifest }” är inte giltig UTF-8: { $path }. +manifest.path_missing_name = Manifestsökvägen ”{ $path }” saknar filnamn. +manifest.open_workspace_failed = Arbetsytan { $workspace } kunde inte öppnas för manifestet { $manifest }. +manifest.foreach.not_iterable = Uttrycket `foreach` går inte att iterera över. +manifest.foreach.serialise_item = Posten i `foreach` kunde inte serialiseras. +manifest.when.empty = Uttrycket `when` får inte vara tomt. +manifest.when.eval_error = Uttrycket `when` ”{ $expr }” kunde inte utvärderas. +manifest.when.template_error = Mallen `when` ”{ $expr }” kunde inte renderas. +manifest.target.vars_not_object = Målets `vars` måste vara ett objekt, men gav { $value }. +manifest.vars.entry_not_object = En `vars`-post i manifestet måste vara ett objekt. +manifest.field_not_string = Fältet ”{ $field }” måste vara en sträng. +manifest.expression.parse_error = Uttrycket { $name } kunde inte tolkas. +manifest.expression.eval_error = Uttrycket { $name } kunde inte utvärderas. + +# Diagnostik för manifestmakron. +manifest.macro.signature_missing_identifier = Makrosignaturen saknar en identifierare. +manifest.macro.signature_missing_params = Makrosignaturen saknar parametrar. +manifest.macro.compile_failed = Makrot { $name } kunde inte kompileras. +manifest.macro.sequence_invalid = Makron måste definieras som en mappning från namn till mallar. +manifest.macro.register_failed = Manifestets makron kunde inte registreras. +manifest.macro.not_initialised = Makromiljön är inte initierad. +manifest.macro.caller_invalid = Makrots anropare måste vara en sträng. +manifest.macro.template_load_failed = Makromallen kunde inte läsas in. +manifest.macro.init_failed = Makromiljön kunde inte initieras. +manifest.macro.missing = Makrot { $name } saknas. + +# Glob-fel i manifestet. +manifest.glob.unmatched_brace = Ogiltigt glob-mönster ”{ $pattern }”: ”{ $character }” saknar motsvarighet på position { $position }. +manifest.glob.invalid_pattern = Ogiltigt glob-mönster ”{ $pattern }”: { $detail }. +manifest.glob.unknown_pattern_error = okänt mönsterfel. +manifest.glob.io_failed = Glob misslyckades för ”{ $pattern }”: { $detail }. +manifest.glob.unknown_io_error = okänt I/O-fel. + +# Fel i den interna representationen. +ir.rule_not_found = Regeln ”{ $rule }” som målet ”{ $target }” hänvisar till hittades inte. +ir.multiple_rules = Målet ”{ $target }” måste hänvisa till exakt en regel, men gav { $rules }. +ir.empty_rule = Målet ”{ $target }” måste hänvisa till en regel. +ir.duplicate_outputs = Dubblerade utdata upptäcktes: { $outputs }. +ir.circular_dependency = Ett cirkulärt beroende upptäcktes: { $cycle }. +ir.action_serialisation = Åtgärden kunde inte serialiseras: { $details }. +ir.invalid_command = Ogiltig interpolering i kommandot: { $snippet }. + +# Fel vid generering av Ninja. +ninja_gen.missing_action = Åtgärden ”{ $id }” som en byggbåge hänvisar till saknas. +ninja_gen.format = Ninja-manifestets utdata kunde inte formateras. + +# Validering av värdmönster. +host_pattern.empty = Värdmönstret får inte vara tomt. +host_pattern.contains_scheme = Värdmönstret ”{ $pattern }” får inte innehålla ett URL-schema. +host_pattern.contains_slash = Värdmönstret ”{ $pattern }” får inte innehålla ”/”. +host_pattern.missing_suffix = Värdmönstret ”{ $pattern }” måste ha ett suffix efter ”*.”. +host_pattern.empty_label = Värdmönstret ”{ $pattern }” innehåller en tom etikett. +host_pattern.invalid_chars = Värdmönstret ”{ $pattern }” innehåller ogiltiga tecken. +host_pattern.invalid_label_edge = Etiketter i värdmönstret ”{ $pattern }” får inte börja eller sluta med ”-”. +host_pattern.label_too_long = Värdmönstret ”{ $pattern }” innehåller en etikett längre än 63 tecken. +host_pattern.too_long = Värdmönstret ”{ $pattern }” överskrider gränsen på 255 tecken. + +# Nätverkspolicy. +network_policy.scheme.empty = Schemat får inte vara tomt. +network_policy.scheme.invalid = Schemat ”{ $scheme }” innehåller ogiltiga tecken. +network_policy.allowlist.empty = Listan över tillåtna värdar får inte vara tom. +network_policy.scheme.not_allowed = Schemat ”{ $scheme }” är inte tillåtet. +network_policy.missing_host = URL-adressen saknar värd. +network_policy.host.blocked = Värden ”{ $host }” blockeras av policyn. +network_policy.host.not_allowlisted = Värden ”{ $host }” finns inte på listan över tillåtna. + +# Konfiguration av standardbiblioteket. +stdlib.config.default_fetch_cache_invalid = Standardsökvägen till fetch-cachen måste vara relativ. +stdlib.config.default_which_cache_invalid = Standardkapaciteten för which-cachen måste vara positiv. +stdlib.config.workspace_root_absolute = Arbetsytans rotsökväg måste vara absolut. +stdlib.config.fetch_response_limit_positive = Svarsgränsen för fetch måste vara positiv. +stdlib.config.command_output_limit_positive = Gränsen för fångad kommandoutdata måste vara positiv. +stdlib.config.command_stream_limit_positive = Strömgränsen för kommandon måste vara positiv. +stdlib.config.which_cache_capacity_positive = Kapaciteten för which-cachen måste vara positiv. +stdlib.config.skip_dir_empty = Poster över överhoppade kataloger får inte vara tomma. +stdlib.config.skip_dir_navigation = Poster över överhoppade kataloger får inte innehålla ”..”. +stdlib.config.skip_dir_separator = Poster över överhoppade kataloger får inte innehålla sökvägsavgränsare. +stdlib.config.fetch_cache_empty = Sökvägen till fetch-cachen får inte vara tom. +stdlib.config.fetch_cache_not_relative = Sökvägen till fetch-cachen måste vara relativ, men gav { $path }. +stdlib.config.fetch_cache_escapes = Sökvägen till fetch-cachen får inte lämna arbetsytan: { $path }. +stdlib.config.open_workspace_root = Den aktuella katalogen kunde inte öppnas som rot för stdlib-arbetsytan. +stdlib.config.resolve_cwd = Den aktuella katalogen kunde inte fastställas som rot för stdlib-arbetsytan. +stdlib.config.cwd_non_utf8 = Den aktuella katalogen innehåller delar som inte är UTF-8: { $path }. + +# Diagnostik för hjälpfunktionen fetch. +stdlib.fetch.url_invalid = Ogiltig URL ”{ $url }”: { $details }. +stdlib.fetch.disallowed = URL-adressen ”{ $url }” är inte tillåten: { $details }. +stdlib.fetch.failed = ”{ $url }” kunde inte hämtas: { $details }. +stdlib.fetch.cache_read_failed = Cacheposten ”{ $name }” kunde inte läsas: { $details }. +stdlib.fetch.cache_open_failed = Cacheposten ”{ $name }” kunde inte öppnas: { $details }. +stdlib.fetch.response_read_failed = Svaret från ”{ $url }” kunde inte läsas: { $details }. +stdlib.fetch.response_buffer_overflow = Buffertspill vid läsning av ”{ $url }”. +stdlib.fetch.cache_write_failed = Cachen för ”{ $url }” kunde inte skrivas: { $details }. +stdlib.fetch.response_limit_exceeded = Svaret från ”{ $url }” överskred gränsen på { $limit } byte. +stdlib.fetch.cache_limit_exceeded = Det cachade svaret ”{ $name }” överskred gränsen på { $limit } byte. +stdlib.fetch.io_failed = { $action } misslyckades för { $path }: { $details }. +stdlib.fetch.action.sync_cache = synkronisera fetch-cachen +stdlib.fetch.action.create_cache_dir = skapa katalogen för fetch-cachen +stdlib.fetch.action.open_cache_dir = öppna katalogen för fetch-cachen +stdlib.fetch.action.stat_cache = slå upp posten i fetch-cachen +stdlib.fetch.action.open_cache_entry = öppna posten i fetch-cachen + +# Diagnostik för kommandohjälparen. +stdlib.command.location = kommandot ”{ $command }” i mallen ”{ $template }” +stdlib.command.spawn_failed = { $location } kunde inte startas: { $details }. +stdlib.command.io_failed = { $location } misslyckades: { $details }. +stdlib.command.closed_input_early = Indata stängdes innan skrivningen till kommandot var klar. +stdlib.command.broken_pipe = Bruten rörledning vid körning av { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } avbröts av en signal. +stdlib.command.exited_with_status = { $location } avslutades med status { $status }. +stdlib.command.output_limit_exceeded = { $location } överskred { $mode }-gränsen på { $limit } byte för { $stream }. +stdlib.command.timeout = { $location } överskred tidsgränsen på { $seconds } sekunder. +stdlib.command.exit_status_suffix = (slutstatus { $status }) +stdlib.command.signal_suffix = (avbrutet av en signal) +stdlib.command.shell.empty = Skalkommandot får inte vara tomt. +stdlib.command.grep.empty_pattern = Mönstret till grep får inte vara tomt. +stdlib.command.grep.flags_not_string = Flaggor till grep måste vara strängar. +stdlib.command.quote.invalid = { $arg } kunde inte citeras: { $details }. +stdlib.command.quote.line_break = Argument med vagnretur eller radmatning kan inte citeras säkert. +stdlib.command.input_undefined = Indatavärdet är odefinierat. +stdlib.command.tempfile.root_required = Arbetsytans rot krävs för att skapa tillfälliga kommandofiler. +stdlib.command.tempfile.create_failed = Den tillfälliga kommandofilen kunde inte skapas: { $details }. +stdlib.command.options.invalid_utf8 = Nyckeln till en kommandoinställning måste vara giltig UTF-8. +stdlib.command.option.mode_not_string = Utdataläget måste vara en sträng. +stdlib.command.options.invalid_type = Kommandoinställningar måste vara ett objekt. +stdlib.command.output.mode_unsupported = Utdataläget ”{ $mode }” stöds inte. +stdlib.command.output.mode.capture = infångning +stdlib.command.output.mode.streaming = strömning +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Diagnostik för sökvägshjälparen. +stdlib.path.io.failed = { $action } misslyckades för { $path } ({ $label }). +stdlib.path.io.failed_with_detail = { $action } misslyckades för { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = { $action } misslyckades för { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = hittades inte +stdlib.path.io.permission_denied = åtkomst nekad +stdlib.path.io.already_exists = finns redan +stdlib.path.io.invalid_input = ogiltig indata +stdlib.path.io.invalid_data = ogiltiga data +stdlib.path.io.timed_out = tidsgränsen löpte ut +stdlib.path.io.interrupted = avbruten +stdlib.path.io.would_block = skulle blockera +stdlib.path.io.write_zero = noll byte skrevs +stdlib.path.io.unexpected_eof = oväntat filslut +stdlib.path.io.broken_pipe = bruten rörledning +stdlib.path.io.connection_refused = anslutningen nekades +stdlib.path.io.connection_reset = anslutningen återställdes +stdlib.path.io.connection_aborted = anslutningen avbröts +stdlib.path.io.not_connected = inte ansluten +stdlib.path.io.addr_in_use = adressen används redan +stdlib.path.io.addr_not_available = adressen är inte tillgänglig +stdlib.path.io.out_of_memory = minnet är slut +stdlib.path.io.unsupported = stöds inte +stdlib.path.io.file_too_large = filen är för stor +stdlib.path.io.resource_busy = resursen är upptagen +stdlib.path.io.executable_busy = den körbara filen är upptagen +stdlib.path.io.deadlock = dödläge +stdlib.path.io.crosses_devices = korsar enheter +stdlib.path.io.too_many_links = för många länkar +stdlib.path.io.invalid_filename = ogiltigt filnamn +stdlib.path.io.arg_list_too_long = argumentlistan är för lång +stdlib.path.io.stale_handle = föråldrat filhandtag i nätverket +stdlib.path.io.storage_full = lagringen är full +stdlib.path.io.not_seekable = går inte att söka i +stdlib.path.io.network_down = nätverket ligger nere +stdlib.path.io.network_unreachable = nätverket kan inte nås +stdlib.path.io.host_unreachable = värden kan inte nås +stdlib.path.io.other = I/O-fel +stdlib.path.action.canonicalize = kanonisera +stdlib.path.action.open_directory = öppna katalog +stdlib.path.action.stat = slå upp +stdlib.path.action.read = läsa +stdlib.path.action.open_file = öppna fil +stdlib.path.with_suffix.empty_separator = with_suffix kräver en avgränsare som inte är tom. +stdlib.path.relative_to.mismatch = { $path } är inte relativ till { $root }. +stdlib.path.expanduser.unsupported = Användarspecifik expansion av ~ stöds inte. +stdlib.path.expanduser.no_home = ~ kan inte expanderas: inga miljövariabler för hemkatalogen är satta. +stdlib.path.contents.unsupported_encoding = Teckenkodningen ”{ $encoding }” stöds inte. +stdlib.path.hash.unsupported_algorithm = Hashalgoritmen ”{ $algorithm }” stöds inte. +stdlib.path.hash.unsupported_algorithm_legacy = Hashalgoritmen ”{ $algorithm }” stöds inte (aktivera funktionen ”{ $feature }”). + +# Diagnostik för samlingshjälpare. +stdlib.collections.flatten.expected_sequence = flatten väntade poster från en sekvens men fann { $kind }. +stdlib.collections.group_by.empty_attribute = group_by kräver ett attribut som inte är tomt. +stdlib.collections.group_by.unresolved = group_by kunde inte slå upp ”{ $attr }” på en post av typen { $kind }. + +# Diagnostik för tidshjälpare. +stdlib.time.offset.invalid = Förskjutningen för now ”{ $offset }” är ogiltig: väntade ”+HH:MM[:SS]” eller ”Z”. +stdlib.time.timedelta.overflow = Spill i timedelta vid addition av { $component }. +stdlib.time.label.weeks = veckor +stdlib.time.label.days = dagar +stdlib.time.label.hours = timmar +stdlib.time.label.minutes = minuter +stdlib.time.label.seconds = sekunder +stdlib.time.label.milliseconds = millisekunder +stdlib.time.label.microseconds = mikrosekunder +stdlib.time.label.nanoseconds = nanosekunder + +# Diagnostik för hjälpfunktionen which. +stdlib.which.not_found = [netsuke::jinja::which::not_found] kommandot ”{ $command }” hittades inte efter genomgång av { $count } PATH-poster. Utdrag: { $preview } +stdlib.which.not_found.hint.cwd_auto = Tomma delar av PATH ignoreras; använd cwd_mode="auto" för att ta med arbetskatalogen. +stdlib.which.not_found.hint.cwd_always = Sätt cwd_mode="always" för att ta med den aktuella katalogen. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] kommandot ”{ $command }” i ”{ $path }” saknas eller är inte körbart. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = PATH-post nr { $index } innehåller tecken som inte är UTF-8; Netsuke kräver UTF-8-sökvägar. +stdlib.which.command.empty = which kräver en sträng som inte är tom. +stdlib.which.cwd_mode.invalid = cwd_mode måste vara ”auto”, ”always” eller ”never”, men gav ”{ $mode }”. +stdlib.which.cwd.resolve_failed = Den aktuella katalogen kunde inte fastställas: { $details }. +stdlib.which.cwd.non_utf8 = Den aktuella katalogen innehåller delar som inte är UTF-8. +stdlib.which.canonicalize_failed = ”{ $path }” kunde inte kanoniseras: { $details }. +stdlib.which.is_executable = Det gick inte att avgöra om ”{ $path }” är körbar: { $details }. +stdlib.which.canonicalize_non_utf8 = Den kanoniska sökvägen innehåller delar som inte är UTF-8. +stdlib.which.workspace_non_utf8 = Arbetsytans sökväg innehåller delar som inte är UTF-8 vid uppslag av kommandot ”{ $command }”: { $path }. +stdlib.which.walkdir_error = Fel vid genomgång av arbetsytan under uppslag av kommandot: { $details }. + +# Registrering av standardbiblioteket. +stdlib.register.open_dir = Den aktuella katalogen kunde inte öppnas för registrering av stdlib. +stdlib.register.resolve_dir = Den aktuella katalogen kunde inte fastställas för registrering av stdlib. +stdlib.register.dir_non_utf8 = Den aktuella katalogen innehåller delar som inte är UTF-8: { $path }. + +# Statusrapportering för tillgängligt utdataläge. +status.state.pending = väntar +status.state.running = pågår +status.state.done = klar +status.state.failed = misslyckades +status.stage.label = Steg { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Uppgift { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Läser manifestfilen +status.stage.initial_yaml_parsing = Tolkar YAML-dokumentet +status.stage.template_expansion = Expanderar malldirektiv +status.stage.final_rendering = Deserialiserar och renderar manifestets värden +status.stage.ir_generation_validation = Bygger och validerar beroendegrafen +status.stage.ninja_synthesis = Skapar Ninja-byggplanen +status.stage.ninja_synthesis_execute = Skapar Ninja-planen och kör { $tool } +status.stage.graph_rendering = Renderar grafartefakten +status.stage.graph_rendering_with_tool = Renderar { $tool } +status.complete = { $tool }: operationen slutfördes. +status.timing.summary_header = Tidssammanfattning per steg: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Total tid för kedjan: { $duration } +status.tool.build = Bygge +status.tool.clean = Rensning +status.tool.graph = Graf +status.tool.graph_html = Graf (HTML) +status.tool.generate = Generering + +# Texter för HTML-renderingen av grafen. +graph.html.title = Netsuke-bygggraf +graph.html.heading = Netsuke-bygggraf +graph.html.description = Bygggraf renderad av Netsuke +graph.html.outline.summary = Mål och beroenden (textöversikt) +graph.html.outline.no_inputs = Inga indata +graph.html.noscript.notice = JavaScript är avstängt. Textöversikten ovan är hela grafen; DOT-källan följer nedan. + +# Semantiska prefix för tillgänglig utdata. +semantic.prefix.error = Fel: +semantic.prefix.warning = Varning: +semantic.prefix.success = Lyckades: +semantic.prefix.info = Info: +semantic.prefix.timing = Tid: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Exempel på pluralformer för översättare. +# Svenskan använder CLDR-kategorierna `one` och `other` precis som källspråket. +example.files_processed = { $count -> + [one] Behandlade { $count } fil. + *[other] Behandlade { $count } filer. +} + +example.errors_found = { $count -> + [0] Inga fel hittades. + [one] { $count } fel hittades. + *[other] { $count } fel hittades. +} diff --git a/locales/th/messages.ftl b/locales/th/messages.ftl new file mode 100644 index 000000000..19ce15002 --- /dev/null +++ b/locales/th/messages.ftl @@ -0,0 +1,395 @@ +# ทรัพยากรการแปลภาษาสำหรับบรรทัดคำสั่งของ Netsuke + +cli.about = Netsuke คอมไพล์ไฟล์รายการ YAML + Jinja ให้เป็นแผนการสร้างของ Ninja +cli.long_about = Netsuke แปลงไฟล์รายการ YAML + Jinja ให้เป็นกราฟ Ninja ที่สร้างซ้ำได้ แล้วเรียกใช้ Ninja ด้วยค่าเริ่มต้นที่ปลอดภัย +cli.usage = { $usage } + +# ข้อความช่วยเหลือของตัวเลือกทั่วไป +cli.flag.file.help = เส้นทางของไฟล์รายการ Netsuke ที่จะใช้ +cli.flag.directory.help = ทำงานเสมือนว่าเริ่มต้นในไดเรกทอรีนี้ +cli.flag.config.help = เส้นทางของไฟล์ตั้งค่า โดยข้ามการค้นหาอัตโนมัติ +cli.flag.jobs.help = กำหนดจำนวนงานสร้างที่ทำงานขนานกัน +cli.flag.verbose.help = เปิดบันทึกวินิจฉัยแบบละเอียดและสรุปเวลาที่ใช้เมื่อเสร็จสิ้น +cli.flag.locale.help = แท็กภาษาสำหรับข้อความบรรทัดคำสั่ง (เช่น en-US, th) +cli.flag.fetch_allow_scheme.help = สกีม URL เพิ่มเติมที่อนุญาตให้ตัวช่วย fetch ใช้ +cli.flag.fetch_allow_host.help = ชื่อโฮสต์ที่อนุญาตเมื่อเปิดการปฏิเสธโดยค่าเริ่มต้น +cli.flag.fetch_block_host.help = ชื่อโฮสต์ที่ถูกปิดกั้นเสมอ แม้จะได้รับอนุญาตจากที่อื่น +cli.flag.fetch_default_deny.help = ปฏิเสธโฮสต์ทั้งหมดโดยค่าเริ่มต้น อนุญาตเฉพาะรายการที่ประกาศไว้ +cli.flag.json.help = แสดงผลเป็น JSON ที่เครื่องอ่านได้ +cli.flag.no_input.help = ไม่อ่านข้อมูลนำเข้าแบบโต้ตอบเลย +cli.flag.color.help = นโยบายการแสดงผลแบบมีสี (auto, always, never) +cli.flag.emoji.help = นโยบายอิโมจิ (auto, always, never) +cli.flag.progress.help = นโยบายการแสดงความคืบหน้า (auto, always, never) +cli.flag.accessibility.help = นโยบายการแสดงผลที่เข้าถึงได้ (auto, on, off) +cli.flag.default_targets.help = เป้าหมายการสร้างโดยปริยายเมื่อไม่ได้ระบุเป้าหมายใด + +# คำอธิบายคำสั่งย่อย +cli.subcommand.build.about = สร้างเป้าหมายที่กำหนดไว้ในไฟล์รายการ (ค่าเริ่มต้น) +cli.subcommand.build.long_about = สร้างเป้าหมายที่ร้องขอ หากไม่ได้ระบุ จะใช้เป้าหมายโดยปริยายของไฟล์รายการ +cli.subcommand.clean.about = ลบสิ่งที่สร้างขึ้นผ่าน Ninja +cli.subcommand.clean.long_about = สร้างไฟล์ Ninja ชั่วคราว จากนั้นเรียกใช้ `ninja -t clean` +cli.subcommand.graph.about = แสดงกราฟการพึ่งพาของการสร้าง รูปแบบเริ่มต้นคือ DOT +cli.subcommand.graph.long_about = ฉายไฟล์รายการ Netsuke ที่แจงแล้วให้เป็นกราฟการสร้างมาตรฐาน แล้วเขียนเป็น Graphviz DOT หรือเขียนเป็นหน้า HTML ที่สมบูรณ์ในตัวเมื่อใช้ `--html` ใช้ `--output <ไฟล์>` เพื่อเขียนลงไฟล์ ส่วน `-` จะเขียนไปยังเอาต์พุตมาตรฐาน +cli.subcommand.generate.about = สร้างไฟล์รายการ Ninja โดยไม่เรียกใช้ Ninja +cli.subcommand.generate.long_about = เขียนไฟล์รายการ Ninja ที่สร้างขึ้นไปยังเอาต์พุตมาตรฐาน หรือไปยังไฟล์ที่เลือกด้วย `--output` + +# ข้อความช่วยเหลือของตัวเลือกในคำสั่งย่อย build +cli.subcommand.build.flag.targets.help = เป้าหมายที่จะสร้าง (หากละไว้ จะใช้ค่าโดยปริยายของไฟล์รายการ) + +# ข้อความช่วยเหลือของตัวเลือกในคำสั่งย่อย graph +cli.subcommand.graph.flag.html.help = แสดงกราฟเป็นหน้า HTML ที่สมบูรณ์ในตัวแทนรูปแบบ DOT +cli.subcommand.graph.flag.output.help = เขียนผลลัพธ์กราฟลงไฟล์ ใช้ `-` สำหรับเอาต์พุตมาตรฐาน + +# ข้อความช่วยเหลือของตัวเลือกในคำสั่งย่อย generate +cli.subcommand.generate.flag.output.help = เขียนไฟล์รายการ Ninja ที่สร้างขึ้นลงไฟล์แทนเอาต์พุตมาตรฐาน + +# ข้อผิดพลาดในการตรวจสอบบรรทัดคำสั่ง +cli.validation.jobs.invalid_number = { $value } ไม่ใช่ตัวเลขที่ถูกต้อง +cli.validation.jobs.out_of_range = จำนวนงานต้องอยู่ระหว่าง { $min } ถึง { $max } +cli.validation.scheme.empty = สกีมต้องไม่ว่างเปล่า +cli.validation.scheme.invalid_start = สกีม “{ $scheme }” ต้องขึ้นต้นด้วยอักษร ASCII +cli.validation.scheme.invalid = สกีมไม่ถูกต้อง: “{ $scheme }” +cli.validation.locale.empty = แท็กภาษาต้องไม่ว่างเปล่า +cli.validation.locale.invalid = แท็กภาษาไม่ถูกต้อง: “{ $locale }” +cli.validation.color.invalid = นโยบายสีไม่ถูกต้อง: “{ $value }” ค่าที่ใช้ได้: auto, always, never +cli.validation.emoji.invalid = นโยบายอิโมจิไม่ถูกต้อง: “{ $value }” ค่าที่ใช้ได้: auto, always, never +cli.validation.progress.invalid = นโยบายความคืบหน้าไม่ถูกต้อง: “{ $value }” ค่าที่ใช้ได้: auto, always, never +cli.validation.accessibility.invalid = นโยบายการเข้าถึงไม่ถูกต้อง: “{ $value }” ค่าที่ใช้ได้: auto, on, off +cli.validation.config.expected_object = ค่าจากบรรทัดคำสั่งควรถูกทำให้เป็นลำดับข้อมูลแบบวัตถุ แต่ได้ { $value } + +# ข้อความแสดงข้อผิดพลาดของ Clap +clap-error-missing-argument = ขาดอาร์กิวเมนต์ที่จำเป็น: { $argument } +clap-error-missing-subcommand = ขาดคำสั่งย่อย ตัวเลือกที่ใช้ได้: { $valid_subcommands } +clap-error-unknown-argument = อาร์กิวเมนต์ที่ไม่รู้จัก: { $argument } +clap-error-invalid-value = ค่าของ { $argument } ไม่ถูกต้อง: { $value } +clap-error-invalid-subcommand = คำสั่งย่อยที่ไม่รู้จัก: { $subcommand } +# หมายเหตุ: value-validation ใช้ถ้อยคำต่างจาก invalid-value เพื่อแยกความล้มเหลว +# ของตัวตรวจสอบที่กำหนดเอง (ErrorKind::ValueValidation) ออกจากชนิดที่ไม่ตรงกัน +# (ErrorKind::InvalidValue) +clap-error-value-validation = การตรวจสอบ { $argument } ล้มเหลว: { $value } + +# ข้อผิดพลาดและบริบทขณะทำงาน +runner.manifest.not_found = ไม่พบไฟล์รายการ “{ $manifest_name }” ใน { $directory } +runner.manifest.not_found.help = โปรดตรวจสอบว่าไฟล์รายการมีอยู่จริง หรือระบุ `--file` ด้วยเส้นทางที่ถูกต้อง +runner.manifest.path_missing_name = เส้นทางไฟล์รายการ “{ $path }” ไม่มีชื่อไฟล์ +runner.manifest.path_utf8 = เส้นทางไฟล์รายการ “{ $path }” ไม่ใช่ UTF-8 ที่ถูกต้อง +runner.manifest.directory_utf8 = เส้นทางไดเรกทอรีของไฟล์รายการ “{ $path }” ไม่ใช่ UTF-8 ที่ถูกต้อง +runner.manifest.directory_label = ไดเรกทอรี `{ $directory }` +runner.manifest.current_directory_label = ไดเรกทอรีปัจจุบัน +runner.context.network_policy = สร้างนโยบายเครือข่ายไม่สำเร็จ +runner.context.load_manifest = โหลดไฟล์รายการที่ { $path } ไม่สำเร็จ +runner.context.serialise_manifest = ทำให้ไฟล์รายการเป็นลำดับข้อมูลไม่สำเร็จ +runner.context.build_graph = สร้างกราฟจากไฟล์รายการไม่สำเร็จ +runner.context.generate_ninja = สร้างไฟล์รายการ Ninja ไม่สำเร็จ +runner.context.render_graph = แสดงผลลัพธ์กราฟไม่สำเร็จ + +runner.io.create_temp_file = สร้างไฟล์ Ninja ชั่วคราวไม่สำเร็จ +runner.io.write_temp_ninja = เขียนไฟล์ Ninja ชั่วคราวไม่สำเร็จ +runner.io.flush_temp_ninja = ล้างบัฟเฟอร์ของไฟล์ Ninja ชั่วคราวไม่สำเร็จ +runner.io.sync_temp_ninja = ประสานข้อมูลไฟล์ Ninja ชั่วคราวไม่สำเร็จ +runner.io.create_parent_dir = สร้างไดเรกทอรีแม่ { $path } ไม่สำเร็จ +runner.io.create_ninja_file = สร้างไฟล์ Ninja ที่ { $path } ไม่สำเร็จ +runner.io.write_ninja_file = เขียนไฟล์ Ninja ที่ { $path } ไม่สำเร็จ +runner.io.flush_ninja_file = ล้างบัฟเฟอร์ของไฟล์ Ninja ที่ { $path } ไม่สำเร็จ +runner.io.sync_ninja_file = ประสานข้อมูลไฟล์ Ninja ที่ { $path } ไม่สำเร็จ +runner.io.open_ambient_dir = เปิดไดเรกทอรีโดยรอบไม่สำเร็จ +runner.io.no_existing_ancestor = ไม่มีไดเรกทอรีระดับบนที่มีอยู่จริงสำหรับ { $path } +runner.io.derive_relative_path = อนุมานเส้นทางสัมพัทธ์ของ Ninja ไม่สำเร็จ +runner.io.non_utf8_path = ไม่รองรับเส้นทางที่ไม่ใช่ UTF-8 (เส้นทาง: { $path }) +runner.io.write_stdout = เขียนไฟล์รายการ Ninja ไปยังเอาต์พุตมาตรฐานไม่สำเร็จ +runner.io.flush_stdout = ล้างบัฟเฟอร์ของเอาต์พุตมาตรฐานไม่สำเร็จ + +# การวินิจฉัยไฟล์รายการ +manifest.parse = การแจงไฟล์รายการล้มเหลว +manifest.structure_error = โครงสร้างของไฟล์รายการผิดพลาดที่ { $name }: { $details } +manifest.yaml.parse = การแจง YAML ผิดพลาดที่บรรทัด { $line } คอลัมน์ { $column }: { $details } +manifest.yaml.label = YAML ไม่ถูกต้อง +manifest.yaml.hint.tabs = YAML ไม่อนุญาตให้ใช้แท็บ ให้ใช้ช่องว่างในการเยื้อง +manifest.yaml.hint.list_item = รายการย่อยของ YAML ต้องขึ้นต้นด้วย “-” และเยื้องอย่างถูกต้อง +manifest.yaml.hint.expected_colon = ดูเหมือนเป็นรายการของการจับคู่ ขาด “:” หลังคีย์ +manifest.yaml.hint.mapping_values = การจับคู่ใน YAML ต้องมีค่าหลัง “:” (หรือบล็อกที่ซ้อนอยู่) +manifest.yaml.hint.invalid_token = โทเคนของ YAML ไม่ถูกต้องหรือไม่คาดคิด +manifest.yaml.hint.escape = โปรดหลีกอักขระแบ็กสแลช หรือลบลำดับหลีกที่ไม่ถูกต้องออก +manifest.env.missing = ยังไม่ได้ตั้งค่าตัวแปรสภาพแวดล้อมที่จำเป็น “{ $name }” +manifest.env.invalid_utf8 = ตัวแปรสภาพแวดล้อม “{ $name }” มี UTF-8 ที่ไม่ถูกต้อง +manifest.vars.not_object = `vars` ของไฟล์รายการต้องเป็นการจับคู่หรือวัตถุ +manifest.read_failed = อ่านไฟล์รายการที่ { $path } ไม่สำเร็จ +manifest.resolve_workspace_root = ระบุรากของพื้นที่ทำงานไม่สำเร็จ +manifest.workspace_non_utf8 = เส้นทางรากของพื้นที่ทำงาน “{ $path }” ไม่ใช่ UTF-8 ที่ถูกต้อง +manifest.path_non_utf8 = เส้นทางของไฟล์รายการ “{ $manifest }” ไม่ใช่ UTF-8 ที่ถูกต้อง: { $path } +manifest.path_missing_name = เส้นทางไฟล์รายการ “{ $path }” ไม่มีชื่อไฟล์ +manifest.open_workspace_failed = เปิดพื้นที่ทำงาน { $workspace } สำหรับไฟล์รายการ { $manifest } ไม่สำเร็จ +manifest.foreach.not_iterable = นิพจน์ `foreach` วนซ้ำไม่ได้ +manifest.foreach.serialise_item = ทำให้สมาชิกของ `foreach` เป็นลำดับข้อมูลไม่สำเร็จ +manifest.when.empty = นิพจน์ `when` ต้องไม่ว่างเปล่า +manifest.when.eval_error = ประเมินค่านิพจน์ `when` “{ $expr }” ไม่สำเร็จ +manifest.when.template_error = แสดงแม่แบบ `when` “{ $expr }” ไม่สำเร็จ +manifest.target.vars_not_object = `vars` ของเป้าหมายต้องเป็นวัตถุ แต่ได้ { $value } +manifest.vars.entry_not_object = รายการ `vars` ของไฟล์รายการต้องเป็นวัตถุ +manifest.field_not_string = เขตข้อมูล “{ $field }” ต้องเป็นสายอักขระ +manifest.expression.parse_error = แจงนิพจน์ { $name } ไม่สำเร็จ +manifest.expression.eval_error = ประเมินค่านิพจน์ { $name } ไม่สำเร็จ + +# การวินิจฉัยแมโครของไฟล์รายการ +manifest.macro.signature_missing_identifier = ลายเซ็นของแมโครขาดตัวระบุ +manifest.macro.signature_missing_params = ลายเซ็นของแมโครขาดพารามิเตอร์ +manifest.macro.compile_failed = คอมไพล์แมโคร { $name } ไม่สำเร็จ +manifest.macro.sequence_invalid = แมโครต้องนิยามเป็นการจับคู่จากชื่อไปยังแม่แบบ +manifest.macro.register_failed = ลงทะเบียนแมโครของไฟล์รายการไม่สำเร็จ +manifest.macro.not_initialised = ยังไม่ได้เตรียมสภาพแวดล้อมของแมโคร +manifest.macro.caller_invalid = ผู้เรียกแมโครต้องเป็นสายอักขระ +manifest.macro.template_load_failed = โหลดแม่แบบของแมโครไม่สำเร็จ +manifest.macro.init_failed = เตรียมสภาพแวดล้อมของแมโครไม่สำเร็จ +manifest.macro.missing = ไม่มีแมโคร { $name } + +# ข้อผิดพลาดของรูปแบบ glob ในไฟล์รายการ +manifest.glob.unmatched_brace = รูปแบบ glob ไม่ถูกต้อง “{ $pattern }”: “{ $character }” ที่ตำแหน่ง { $position } ไม่มีคู่ +manifest.glob.invalid_pattern = รูปแบบ glob ไม่ถูกต้อง “{ $pattern }”: { $detail } +manifest.glob.unknown_pattern_error = ข้อผิดพลาดของรูปแบบที่ไม่รู้จัก +manifest.glob.io_failed = glob ล้มเหลวสำหรับ “{ $pattern }”: { $detail } +manifest.glob.unknown_io_error = ข้อผิดพลาดรับส่งข้อมูลที่ไม่รู้จัก + +# ข้อผิดพลาดของรูปแทนระดับกลาง +ir.rule_not_found = ไม่พบกฎ “{ $rule }” ที่เป้าหมาย “{ $target }” อ้างถึง +ir.multiple_rules = เป้าหมาย “{ $target }” ต้องอ้างถึงกฎเพียงข้อเดียว แต่ได้ { $rules } +ir.empty_rule = เป้าหมาย “{ $target }” ต้องอ้างถึงกฎหนึ่งข้อ +ir.duplicate_outputs = พบผลลัพธ์ซ้ำกัน: { $outputs } +ir.circular_dependency = พบการพึ่งพาแบบวงกลม: { $cycle } +ir.action_serialisation = ทำให้การกระทำเป็นลำดับข้อมูลไม่สำเร็จ: { $details } +ir.invalid_command = การแทรกค่าในคำสั่งไม่ถูกต้อง: { $snippet } + +# ข้อผิดพลาดในการสร้างไฟล์ Ninja +ninja_gen.missing_action = ไม่มีการกระทำ “{ $id }” ที่เส้นเชื่อมของการสร้างอ้างถึง +ninja_gen.format = จัดรูปแบบผลลัพธ์ของไฟล์รายการ Ninja ไม่สำเร็จ + +# การตรวจสอบรูปแบบโฮสต์ +host_pattern.empty = รูปแบบโฮสต์ต้องไม่ว่างเปล่า +host_pattern.contains_scheme = รูปแบบโฮสต์ “{ $pattern }” ต้องไม่มีสกีม URL +host_pattern.contains_slash = รูปแบบโฮสต์ “{ $pattern }” ต้องไม่มี “/” +host_pattern.missing_suffix = รูปแบบโฮสต์ “{ $pattern }” ต้องมีส่วนต่อท้ายหลัง “*.” +host_pattern.empty_label = รูปแบบโฮสต์ “{ $pattern }” มีป้ายกำกับว่างเปล่า +host_pattern.invalid_chars = รูปแบบโฮสต์ “{ $pattern }” มีอักขระที่ไม่ถูกต้อง +host_pattern.invalid_label_edge = ป้ายกำกับของรูปแบบโฮสต์ “{ $pattern }” ต้องไม่ขึ้นต้นหรือลงท้ายด้วย “-” +host_pattern.label_too_long = รูปแบบโฮสต์ “{ $pattern }” มีป้ายกำกับยาวเกิน 63 อักขระ +host_pattern.too_long = รูปแบบโฮสต์ “{ $pattern }” เกินขีดจำกัด 255 อักขระ + +# นโยบายเครือข่าย +network_policy.scheme.empty = สกีมต้องไม่ว่างเปล่า +network_policy.scheme.invalid = สกีม “{ $scheme }” มีอักขระที่ไม่ถูกต้อง +network_policy.allowlist.empty = รายชื่อโฮสต์ที่อนุญาตต้องไม่ว่างเปล่า +network_policy.scheme.not_allowed = ไม่อนุญาตให้ใช้สกีม “{ $scheme }” +network_policy.missing_host = URL ไม่มีโฮสต์ +network_policy.host.blocked = โฮสต์ “{ $host }” ถูกนโยบายปิดกั้น +network_policy.host.not_allowlisted = โฮสต์ “{ $host }” ไม่อยู่ในรายชื่อที่อนุญาต + +# การตั้งค่าไลบรารีมาตรฐาน +stdlib.config.default_fetch_cache_invalid = เส้นทางแคชของ fetch โดยปริยายต้องเป็นเส้นทางสัมพัทธ์ +stdlib.config.default_which_cache_invalid = ความจุแคชของ which โดยปริยายต้องเป็นจำนวนบวก +stdlib.config.workspace_root_absolute = เส้นทางรากของพื้นที่ทำงานต้องเป็นเส้นทางสัมบูรณ์ +stdlib.config.fetch_response_limit_positive = ขีดจำกัดการตอบสนองของ fetch ต้องเป็นจำนวนบวก +stdlib.config.command_output_limit_positive = ขีดจำกัดการเก็บผลลัพธ์ของคำสั่งต้องเป็นจำนวนบวก +stdlib.config.command_stream_limit_positive = ขีดจำกัดสายข้อมูลของคำสั่งต้องเป็นจำนวนบวก +stdlib.config.which_cache_capacity_positive = ความจุแคชของ which ต้องเป็นจำนวนบวก +stdlib.config.skip_dir_empty = รายการไดเรกทอรีที่ข้ามต้องไม่ว่างเปล่า +stdlib.config.skip_dir_navigation = รายการไดเรกทอรีที่ข้ามต้องไม่มี “..” +stdlib.config.skip_dir_separator = รายการไดเรกทอรีที่ข้ามต้องไม่มีตัวคั่นเส้นทาง +stdlib.config.fetch_cache_empty = เส้นทางแคชของ fetch ต้องไม่ว่างเปล่า +stdlib.config.fetch_cache_not_relative = เส้นทางแคชของ fetch ต้องเป็นเส้นทางสัมพัทธ์ แต่ได้ { $path } +stdlib.config.fetch_cache_escapes = เส้นทางแคชของ fetch ต้องไม่ออกนอกพื้นที่ทำงาน: { $path } +stdlib.config.open_workspace_root = เปิดไดเรกทอรีปัจจุบันเป็นรากของพื้นที่ทำงาน stdlib ไม่สำเร็จ +stdlib.config.resolve_cwd = ระบุไดเรกทอรีปัจจุบันเป็นรากของพื้นที่ทำงาน stdlib ไม่สำเร็จ +stdlib.config.cwd_non_utf8 = ไดเรกทอรีปัจจุบันมีส่วนที่ไม่ใช่ UTF-8: { $path } + +# การวินิจฉัยของตัวช่วย fetch +stdlib.fetch.url_invalid = URL ไม่ถูกต้อง “{ $url }”: { $details } +stdlib.fetch.disallowed = ไม่อนุญาตให้ใช้ URL “{ $url }”: { $details } +stdlib.fetch.failed = ดึงข้อมูลจาก “{ $url }” ไม่สำเร็จ: { $details } +stdlib.fetch.cache_read_failed = อ่านรายการแคช “{ $name }” ไม่สำเร็จ: { $details } +stdlib.fetch.cache_open_failed = เปิดรายการแคช “{ $name }” ไม่สำเร็จ: { $details } +stdlib.fetch.response_read_failed = อ่านการตอบสนองจาก “{ $url }” ไม่สำเร็จ: { $details } +stdlib.fetch.response_buffer_overflow = บัฟเฟอร์ล้นขณะอ่าน “{ $url }” +stdlib.fetch.cache_write_failed = เขียนแคชสำหรับ “{ $url }” ไม่สำเร็จ: { $details } +stdlib.fetch.response_limit_exceeded = การตอบสนองจาก “{ $url }” เกินขีดจำกัด { $limit } ไบต์ +stdlib.fetch.cache_limit_exceeded = การตอบสนองที่แคชไว้ “{ $name }” เกินขีดจำกัด { $limit } ไบต์ +stdlib.fetch.io_failed = การกระทำ “{ $action }” ล้มเหลวสำหรับ { $path }: { $details } +stdlib.fetch.action.sync_cache = ประสานข้อมูลแคชของ fetch +stdlib.fetch.action.create_cache_dir = สร้างไดเรกทอรีแคชของ fetch +stdlib.fetch.action.open_cache_dir = เปิดไดเรกทอรีแคชของ fetch +stdlib.fetch.action.stat_cache = อ่านข้อมูลของรายการแคช fetch +stdlib.fetch.action.open_cache_entry = เปิดรายการแคชของ fetch + +# การวินิจฉัยของตัวช่วยด้านคำสั่ง +stdlib.command.location = คำสั่ง “{ $command }” ในแม่แบบ “{ $template }” +stdlib.command.spawn_failed = เริ่ม { $location } ไม่สำเร็จ: { $details } +stdlib.command.io_failed = { $location } ล้มเหลว: { $details } +stdlib.command.closed_input_early = ข้อมูลนำเข้าปิดลงก่อนที่การเขียนไปยังคำสั่งจะเสร็จ +stdlib.command.broken_pipe = ท่อส่งข้อมูลขาดขณะเรียกใช้ { $location }: { $details } +stdlib.command.terminated_by_signal = { $location } ถูกยุติด้วยสัญญาณ +stdlib.command.exited_with_status = { $location } สิ้นสุดด้วยสถานะ { $status } +stdlib.command.output_limit_exceeded = { $location } เกินขีดจำกัด { $mode } ที่ { $limit } ไบต์สำหรับ { $stream } +stdlib.command.timeout = { $location } เกินเวลาที่กำหนด { $seconds } วินาที +stdlib.command.exit_status_suffix = (สถานะการออก { $status }) +stdlib.command.signal_suffix = (ถูกยุติด้วยสัญญาณ) +stdlib.command.shell.empty = คำสั่งเชลล์ต้องไม่ว่างเปล่า +stdlib.command.grep.empty_pattern = รูปแบบของ grep ต้องไม่ว่างเปล่า +stdlib.command.grep.flags_not_string = แฟล็กของ grep ต้องเป็นสายอักขระ +stdlib.command.quote.invalid = ใส่เครื่องหมายอัญประกาศให้ { $arg } ไม่สำเร็จ: { $details } +stdlib.command.quote.line_break = อาร์กิวเมนต์ที่มีอักขระขึ้นบรรทัดใหม่หรือปัดแคร่ไม่สามารถใส่เครื่องหมายอัญประกาศได้อย่างปลอดภัย +stdlib.command.input_undefined = ค่าที่นำเข้ายังไม่ได้นิยาม +stdlib.command.tempfile.root_required = การสร้างไฟล์ชั่วคราวของคำสั่งต้องใช้รากของพื้นที่ทำงาน +stdlib.command.tempfile.create_failed = สร้างไฟล์ชั่วคราวของคำสั่งไม่สำเร็จ: { $details } +stdlib.command.options.invalid_utf8 = คีย์ของตัวเลือกคำสั่งต้องเป็น UTF-8 ที่ถูกต้อง +stdlib.command.option.mode_not_string = โหมดการแสดงผลต้องเป็นสายอักขระ +stdlib.command.options.invalid_type = ตัวเลือกของคำสั่งต้องเป็นวัตถุ +stdlib.command.output.mode_unsupported = ไม่รองรับโหมดการแสดงผล “{ $mode }” +stdlib.command.output.mode.capture = การเก็บผลลัพธ์ +stdlib.command.output.mode.streaming = การส่งเป็นสายข้อมูล +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# การวินิจฉัยของตัวช่วยด้านเส้นทาง +stdlib.path.io.failed = การกระทำ “{ $action }” ล้มเหลวสำหรับ { $path } ({ $label }) +stdlib.path.io.failed_with_detail = การกระทำ “{ $action }” ล้มเหลวสำหรับ { $path }: { $detail } +stdlib.path.io.failed_with_label_and_detail = การกระทำ “{ $action }” ล้มเหลวสำหรับ { $path } ({ $label }): { $detail } +stdlib.path.io.not_found = ไม่พบ +stdlib.path.io.permission_denied = ถูกปฏิเสธสิทธิ์ +stdlib.path.io.already_exists = มีอยู่แล้ว +stdlib.path.io.invalid_input = ข้อมูลนำเข้าไม่ถูกต้อง +stdlib.path.io.invalid_data = ข้อมูลไม่ถูกต้อง +stdlib.path.io.timed_out = หมดเวลา +stdlib.path.io.interrupted = ถูกขัดจังหวะ +stdlib.path.io.would_block = จะทำให้เกิดการรอ +stdlib.path.io.write_zero = เขียนได้ศูนย์ไบต์ +stdlib.path.io.unexpected_eof = จบไฟล์โดยไม่คาดคิด +stdlib.path.io.broken_pipe = ท่อส่งข้อมูลขาด +stdlib.path.io.connection_refused = การเชื่อมต่อถูกปฏิเสธ +stdlib.path.io.connection_reset = การเชื่อมต่อถูกรีเซ็ต +stdlib.path.io.connection_aborted = การเชื่อมต่อถูกยกเลิก +stdlib.path.io.not_connected = ยังไม่ได้เชื่อมต่อ +stdlib.path.io.addr_in_use = ที่อยู่ถูกใช้งานอยู่ +stdlib.path.io.addr_not_available = ที่อยู่ใช้งานไม่ได้ +stdlib.path.io.out_of_memory = หน่วยความจำไม่พอ +stdlib.path.io.unsupported = ไม่รองรับ +stdlib.path.io.file_too_large = ไฟล์ใหญ่เกินไป +stdlib.path.io.resource_busy = ทรัพยากรไม่ว่าง +stdlib.path.io.executable_busy = ไฟล์ที่เรียกใช้ได้ไม่ว่าง +stdlib.path.io.deadlock = การติดตายพร้อมกัน +stdlib.path.io.crosses_devices = ข้ามอุปกรณ์ +stdlib.path.io.too_many_links = มีลิงก์มากเกินไป +stdlib.path.io.invalid_filename = ชื่อไฟล์ไม่ถูกต้อง +stdlib.path.io.arg_list_too_long = รายการอาร์กิวเมนต์ยาวเกินไป +stdlib.path.io.stale_handle = ตัวชี้ไฟล์เครือข่ายหมดอายุ +stdlib.path.io.storage_full = พื้นที่จัดเก็บเต็ม +stdlib.path.io.not_seekable = เลื่อนตำแหน่งไม่ได้ +stdlib.path.io.network_down = เครือข่ายไม่ทำงาน +stdlib.path.io.network_unreachable = เข้าถึงเครือข่ายไม่ได้ +stdlib.path.io.host_unreachable = เข้าถึงโฮสต์ไม่ได้ +stdlib.path.io.other = ข้อผิดพลาดรับส่งข้อมูล +stdlib.path.action.canonicalize = การทำให้เป็นรูปแบบมาตรฐาน +stdlib.path.action.open_directory = การเปิดไดเรกทอรี +stdlib.path.action.stat = การอ่านข้อมูล +stdlib.path.action.read = การอ่าน +stdlib.path.action.open_file = การเปิดไฟล์ +stdlib.path.with_suffix.empty_separator = with_suffix ต้องมีตัวคั่นที่ไม่ว่างเปล่า +stdlib.path.relative_to.mismatch = { $path } ไม่ได้สัมพัทธ์กับ { $root } +stdlib.path.expanduser.unsupported = ไม่รองรับการขยาย ~ สำหรับผู้ใช้รายใดรายหนึ่ง +stdlib.path.expanduser.no_home = ขยาย ~ ไม่ได้: ไม่มีการตั้งค่าตัวแปรสภาพแวดล้อมของไดเรกทอรีบ้าน +stdlib.path.contents.unsupported_encoding = ไม่รองรับการเข้ารหัส “{ $encoding }” +stdlib.path.hash.unsupported_algorithm = ไม่รองรับขั้นตอนวิธีแฮช “{ $algorithm }” +stdlib.path.hash.unsupported_algorithm_legacy = ไม่รองรับขั้นตอนวิธีแฮช “{ $algorithm }” (โปรดเปิดใช้คุณลักษณะ “{ $feature }”) + +# การวินิจฉัยของตัวช่วยด้านคอลเลกชัน +stdlib.collections.flatten.expected_sequence = flatten คาดว่าจะพบสมาชิกของลำดับ แต่พบ { $kind } +stdlib.collections.group_by.empty_attribute = group_by ต้องมีแอตทริบิวต์ที่ไม่ว่างเปล่า +stdlib.collections.group_by.unresolved = group_by หา “{ $attr }” ในสมาชิกชนิด { $kind } ไม่พบ + +# การวินิจฉัยของตัวช่วยด้านเวลา +stdlib.time.offset.invalid = ค่าเหลื่อมของ now “{ $offset }” ไม่ถูกต้อง: ต้องเป็น “+HH:MM[:SS]” หรือ “Z” +stdlib.time.timedelta.overflow = timedelta ล้นขณะบวก { $component } +stdlib.time.label.weeks = สัปดาห์ +stdlib.time.label.days = วัน +stdlib.time.label.hours = ชั่วโมง +stdlib.time.label.minutes = นาที +stdlib.time.label.seconds = วินาที +stdlib.time.label.milliseconds = มิลลิวินาที +stdlib.time.label.microseconds = ไมโครวินาที +stdlib.time.label.nanoseconds = นาโนวินาที + +# การวินิจฉัยของตัวช่วย which +stdlib.which.not_found = [netsuke::jinja::which::not_found] ไม่พบคำสั่ง “{ $command }” หลังตรวจรายการใน PATH แล้ว { $count } รายการ ตัวอย่าง: { $preview } +stdlib.which.not_found.hint.cwd_auto = ส่วนที่ว่างเปล่าใน PATH จะถูกละเว้น หากต้องการรวมไดเรกทอรีทำงาน ให้ใช้ cwd_mode="auto" +stdlib.which.not_found.hint.cwd_always = หากต้องการรวมไดเรกทอรีปัจจุบัน ให้ตั้งค่า cwd_mode="always" +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] คำสั่ง “{ $command }” ที่ “{ $path }” ไม่มีอยู่หรือเรียกใช้ไม่ได้ +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = <ว่างเปล่า> +stdlib.which.path_entry.non_utf8 = รายการที่ { $index } ใน PATH มีอักขระที่ไม่ใช่ UTF-8 Netsuke ต้องใช้เส้นทางแบบ UTF-8 +stdlib.which.command.empty = which ต้องใช้สายอักขระที่ไม่ว่างเปล่า +stdlib.which.cwd_mode.invalid = cwd_mode ต้องเป็น “auto” “always” หรือ “never” แต่ได้ “{ $mode }” +stdlib.which.cwd.resolve_failed = ระบุไดเรกทอรีปัจจุบันไม่สำเร็จ: { $details } +stdlib.which.cwd.non_utf8 = ไดเรกทอรีปัจจุบันมีส่วนที่ไม่ใช่ UTF-8 +stdlib.which.canonicalize_failed = ทำให้ “{ $path }” เป็นรูปแบบมาตรฐานไม่สำเร็จ: { $details } +stdlib.which.is_executable = ตรวจสอบไม่ได้ว่า “{ $path }” เรียกใช้ได้หรือไม่: { $details } +stdlib.which.canonicalize_non_utf8 = เส้นทางมาตรฐานมีส่วนที่ไม่ใช่ UTF-8 +stdlib.which.workspace_non_utf8 = ขณะแก้ปัญหาคำสั่ง “{ $command }” เส้นทางของพื้นที่ทำงานมีส่วนที่ไม่ใช่ UTF-8: { $path } +stdlib.which.walkdir_error = เกิดข้อผิดพลาดขณะท่องพื้นที่ทำงานเพื่อค้นหาคำสั่ง: { $details } + +# การลงทะเบียนไลบรารีมาตรฐาน +stdlib.register.open_dir = เปิดไดเรกทอรีปัจจุบันเพื่อลงทะเบียน stdlib ไม่สำเร็จ +stdlib.register.resolve_dir = ระบุไดเรกทอรีปัจจุบันเพื่อลงทะเบียน stdlib ไม่สำเร็จ +stdlib.register.dir_non_utf8 = ไดเรกทอรีปัจจุบันมีส่วนที่ไม่ใช่ UTF-8: { $path } + +# การรายงานสถานะสำหรับโหมดการแสดงผลที่เข้าถึงได้ +status.state.pending = รอดำเนินการ +status.state.running = กำลังดำเนินการ +status.state.done = เสร็จแล้ว +status.state.failed = ล้มเหลว +status.stage.label = ขั้นที่ { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = งานที่ { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = กำลังอ่านไฟล์รายการ +status.stage.initial_yaml_parsing = กำลังแจงเอกสาร YAML +status.stage.template_expansion = กำลังขยายคำสั่งของแม่แบบ +status.stage.final_rendering = กำลังแปลงกลับและแสดงค่าจากไฟล์รายการ +status.stage.ir_generation_validation = กำลังสร้างและตรวจสอบกราฟการพึ่งพา +status.stage.ninja_synthesis = กำลังสังเคราะห์แผนการสร้างของ Ninja +status.stage.ninja_synthesis_execute = กำลังสังเคราะห์แผนของ Ninja และเรียกใช้ { $tool } +status.stage.graph_rendering = กำลังแสดงผลลัพธ์กราฟ +status.stage.graph_rendering_with_tool = กำลังแสดง { $tool } +status.complete = { $tool } เสร็จสมบูรณ์ +status.timing.summary_header = สรุปเวลาตามขั้นตอน: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = เวลารวมของสายงาน: { $duration } +status.tool.build = การสร้าง +status.tool.clean = การล้าง +status.tool.graph = กราฟ +status.tool.graph_html = กราฟ (HTML) +status.tool.generate = การสร้างไฟล์ + +# ข้อความของตัวแสดงกราฟเป็น HTML +graph.html.title = กราฟการสร้างของ Netsuke +graph.html.heading = กราฟการสร้างของ Netsuke +graph.html.description = กราฟการสร้างที่แสดงโดย Netsuke +graph.html.outline.summary = เป้าหมายและการพึ่งพา (โครงร่างข้อความ) +graph.html.outline.no_inputs = ไม่มีข้อมูลนำเข้า +graph.html.noscript.notice = JavaScript ถูกปิดอยู่ โครงร่างข้อความด้านบนคือกราฟทั้งหมด ถัดไปเป็นซอร์ส DOT + +# คำนำหน้าเชิงความหมายสำหรับการแสดงผลที่เข้าถึงได้ +semantic.prefix.error = ข้อผิดพลาด: +semantic.prefix.warning = คำเตือน: +semantic.prefix.success = สำเร็จ: +semantic.prefix.info = ข้อมูล: +semantic.prefix.timing = เวลา: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# ตัวอย่างรูปพหูพจน์สำหรับผู้แปล +# ภาษาไทยไม่มีการผันรูปพหูพจน์ CLDR จึงมีหมวดเดียวคือ `other` +example.files_processed = { $count -> + *[other] ประมวลผลแล้ว { $count } ไฟล์ +} + +example.errors_found = { $count -> + [0] ไม่พบข้อผิดพลาด + *[other] พบข้อผิดพลาด { $count } รายการ +} diff --git a/locales/tr/messages.ftl b/locales/tr/messages.ftl new file mode 100644 index 000000000..549f4b4f4 --- /dev/null +++ b/locales/tr/messages.ftl @@ -0,0 +1,398 @@ +# Netsuke komut satırı için yerelleştirme kaynakları. + +cli.about = Netsuke, YAML + Jinja bildirimlerini Ninja derleme planlarına derler. +cli.long_about = Netsuke, YAML + Jinja bildirimlerini yeniden üretilebilir Ninja çizgelerine dönüştürür ve Ninja'yı güvenli varsayılanlarla çalıştırır. +cli.usage = { $usage } + +# Genel seçeneklerin yardım metni. +cli.flag.file.help = Kullanılacak Netsuke bildirim dosyasının yolu. +cli.flag.directory.help = Bu dizinde başlatılmış gibi çalıştır. +cli.flag.config.help = Otomatik aramayı atlayarak kullanılacak yapılandırma dosyasının yolu. +cli.flag.jobs.help = Koşut derleme işlerinin sayısını belirle. +cli.flag.verbose.help = Ayrıntılı tanılama günlüğünü ve bitişteki süre özetlerini etkinleştir. +cli.flag.locale.help = Komut satırı metinleri için dil etiketi (örneğin: en-US, tr). +cli.flag.fetch_allow_scheme.help = fetch yardımcısının kullanabileceği ek URL şemaları. +cli.flag.fetch_allow_host.help = Varsayılan reddetme açıkken izin verilen makine adları. +cli.flag.fetch_block_host.help = Başka yerde izin verilse bile her zaman engellenen makine adları. +cli.flag.fetch_default_deny.help = Varsayılan olarak tüm makineleri reddet; yalnızca bildirilen listeye izin ver. +cli.flag.json.help = Makinece okunabilir JSON çıktısı üret. +cli.flag.no_input.help = Etkileşimli girdi hiçbir zaman okunmasın. +cli.flag.color.help = Renkli çıktı ilkesi (auto, always, never). +cli.flag.emoji.help = Emoji ilkesi (auto, always, never). +cli.flag.progress.help = İlerleme gösterimi ilkesi (auto, always, never). +cli.flag.accessibility.help = Erişilebilir çıktı ilkesi (auto, on, off). +cli.flag.default_targets.help = Hiçbiri belirtilmediğinde kullanılacak varsayılan derleme hedefleri. + +# Alt komut açıklamaları. +cli.subcommand.build.about = Bildirimde tanımlı hedefleri derle (varsayılan). +cli.subcommand.build.long_about = İstenen hedefleri derle; hiçbiri verilmezse bildirimdeki varsayılan hedefleri kullan. +cli.subcommand.clean.about = Derleme ürünlerini Ninja aracılığıyla kaldır. +cli.subcommand.clean.long_about = Geçici bir Ninja dosyası oluştur, ardından `ninja -t clean` komutunu çalıştır. +cli.subcommand.graph.about = Derleme bağımlılık çizgesini yaz. Varsayılan biçim DOT'tur. +cli.subcommand.graph.long_about = Ayrıştırılan Netsuke bildirimini kurallı bir derleme çizgesine dönüştür ve Graphviz DOT olarak ya da `--html` ile kendi kendine yeten bir HTML sayfası olarak yaz. Dosyaya yazmak için `--output ` kullanın; `-` standart çıktıya yazar. +cli.subcommand.generate.about = Ninja'yı çalıştırmadan Ninja bildirimini üret. +cli.subcommand.generate.long_about = Üretilen Ninja bildirimini standart çıktıya ya da `--output` ile seçilen dosyaya yaz. + +# build alt komutunun seçenekleri için yardım metni. +cli.subcommand.build.flag.targets.help = Derlenecek hedefler (belirtilmezse bildirimdeki varsayılanlar kullanılır). + +# graph alt komutunun seçenekleri için yardım metni. +cli.subcommand.graph.flag.html.help = Çizgeyi DOT yerine kendi kendine yeten bir HTML sayfası olarak işle. +cli.subcommand.graph.flag.output.help = Çizge ürününü DOSYA'ya yaz; standart çıktı için `-` kullanın. + +# generate alt komutunun seçenekleri için yardım metni. +cli.subcommand.generate.flag.output.help = Üretilen Ninja bildirimini standart çıktı yerine DOSYA'ya yaz. + +# Komut satırı doğrulama hataları. +cli.validation.jobs.invalid_number = { $value } geçerli bir sayı değil. +cli.validation.jobs.out_of_range = İş sayısı { $min } ile { $max } arasında olmalıdır. +cli.validation.scheme.empty = Şema boş olmamalıdır. +cli.validation.scheme.invalid_start = "{ $scheme }" şeması bir ASCII harfiyle başlamalıdır. +cli.validation.scheme.invalid = Geçersiz şema: "{ $scheme }". +cli.validation.locale.empty = Dil etiketi boş olmamalıdır. +cli.validation.locale.invalid = Geçersiz dil etiketi: "{ $locale }". +cli.validation.color.invalid = Geçersiz renk ilkesi: "{ $value }". Geçerli seçenekler: auto, always, never. +cli.validation.emoji.invalid = Geçersiz emoji ilkesi: "{ $value }". Geçerli seçenekler: auto, always, never. +cli.validation.progress.invalid = Geçersiz ilerleme ilkesi: "{ $value }". Geçerli seçenekler: auto, always, never. +cli.validation.accessibility.invalid = Geçersiz erişilebilirlik ilkesi: "{ $value }". Geçerli seçenekler: auto, on, off. +cli.validation.config.expected_object = Komut satırı değerlerinin bir nesneye serileştirilmesi bekleniyordu, { $value } alındı. + +# Clap hata iletileri. +clap-error-missing-argument = Zorunlu bağımsız değişken eksik: { $argument } +clap-error-missing-subcommand = Alt komut eksik. Kullanılabilir seçenekler: { $valid_subcommands } +clap-error-unknown-argument = Bilinmeyen bağımsız değişken: { $argument } +clap-error-invalid-value = { $argument } için geçersiz değer: { $value } +clap-error-invalid-subcommand = Bilinmeyen alt komut: { $subcommand } +# Not: value-validation, özel doğrulayıcı hatalarını +# (ErrorKind::ValueValidation) tür uyuşmazlıklarından +# (ErrorKind::InvalidValue) ayırmak için invalid-value'dan farklı yazılmıştır. +clap-error-value-validation = { $argument } için doğrulama başarısız: { $value } + +# Çalıştırma hataları ve bağlamı. +runner.manifest.not_found = "{ $manifest_name }" bildirimi { $directory } içinde bulunamadı. +runner.manifest.not_found.help = Bildirimin var olduğundan emin olun ya da `--file` seçeneğini doğru yolla verin. +runner.manifest.path_missing_name = "{ $path }" bildirim yolunda dosya adı yok. +runner.manifest.path_utf8 = "{ $path }" bildirim yolu geçerli UTF-8 değil. +runner.manifest.directory_utf8 = "{ $path }" bildirim dizini yolu geçerli UTF-8 değil. +runner.manifest.directory_label = `{ $directory }` dizini +runner.manifest.current_directory_label = geçerli dizin +runner.context.network_policy = Ağ ilkesi oluşturulamadı. +runner.context.load_manifest = { $path } konumundaki bildirim yüklenemedi. +runner.context.serialise_manifest = Bildirim serileştirilemedi. +runner.context.build_graph = Bildirimden çizge oluşturulamadı. +runner.context.generate_ninja = Ninja bildirimi üretilemedi. +runner.context.render_graph = Çizge ürünü işlenemedi. + +runner.io.create_temp_file = Geçici Ninja dosyası oluşturulamadı. +runner.io.write_temp_ninja = Geçici Ninja dosyası yazılamadı. +runner.io.flush_temp_ninja = Geçici Ninja dosyasının arabelleği boşaltılamadı. +runner.io.sync_temp_ninja = Geçici Ninja dosyası eşitlenemedi. +runner.io.create_parent_dir = { $path } üst dizini oluşturulamadı. +runner.io.create_ninja_file = { $path } konumunda Ninja dosyası oluşturulamadı. +runner.io.write_ninja_file = { $path } konumundaki Ninja dosyası yazılamadı. +runner.io.flush_ninja_file = { $path } konumundaki Ninja dosyasının arabelleği boşaltılamadı. +runner.io.sync_ninja_file = { $path } konumundaki Ninja dosyası eşitlenemedi. +runner.io.open_ambient_dir = Çevreleyen dizin açılamadı. +runner.io.no_existing_ancestor = { $path } için var olan bir üst dizin yok. +runner.io.derive_relative_path = Göreli Ninja yolu türetilemedi. +runner.io.non_utf8_path = UTF-8 olmayan yollar desteklenmiyor (yol: { $path }). +runner.io.write_stdout = Ninja bildirimi standart çıktıya yazılamadı. +runner.io.flush_stdout = Standart çıktının arabelleği boşaltılamadı. + +# Bildirim tanılaması. +manifest.parse = Bildirimin ayrıştırılması başarısız oldu. +manifest.structure_error = { $name } konumunda bildirim yapısı hatası: { $details } +manifest.yaml.parse = { $line }. satır, { $column }. sütunda YAML ayrıştırma hatası: { $details } +manifest.yaml.label = geçersiz YAML +manifest.yaml.hint.tabs = YAML sekmelere izin vermez; girinti için boşluk kullanın. +manifest.yaml.hint.list_item = YAML liste öğeleri "-" ile başlamalı ve düzgün girintilenmelidir. +manifest.yaml.hint.expected_colon = Bu bir eşleme girdisine benziyor; anahtardan sonra ":" eksik. +manifest.yaml.hint.mapping_values = YAML eşlemeleri ":" işaretinden sonra bir değer (ya da iç içe blok) ister. +manifest.yaml.hint.invalid_token = YAML belirteci geçersiz ya da beklenmedik. +manifest.yaml.hint.escape = Ters eğik çizgileri kaçırın ya da geçersiz kaçış dizilerini kaldırın. +manifest.env.missing = Gerekli "{ $name }" ortam değişkeni ayarlanmamış. +manifest.env.invalid_utf8 = "{ $name }" ortam değişkeni geçersiz UTF-8 içeriyor. +manifest.vars.not_object = Bildirimin `vars` alanı bir eşleme ya da nesne olmalıdır. +manifest.read_failed = { $path } konumundaki bildirim okunamadı. +manifest.resolve_workspace_root = Çalışma alanının kökü belirlenemedi. +manifest.workspace_non_utf8 = "{ $path }" çalışma alanı kök yolu geçerli UTF-8 değil. +manifest.path_non_utf8 = "{ $manifest }" bildiriminin yolu geçerli UTF-8 değil: { $path }. +manifest.path_missing_name = "{ $path }" bildirim yolunda dosya adı yok. +manifest.open_workspace_failed = { $manifest } bildirimi için { $workspace } çalışma alanı açılamadı. +manifest.foreach.not_iterable = `foreach` ifadesi yinelenebilir değil. +manifest.foreach.serialise_item = `foreach` öğesi serileştirilemedi. +manifest.when.empty = `when` ifadesi boş olmamalıdır. +manifest.when.eval_error = "{ $expr }" `when` ifadesi değerlendirilemedi. +manifest.when.template_error = "{ $expr }" `when` şablonu işlenemedi. +manifest.target.vars_not_object = Hedefin `vars` alanı bir nesne olmalıdır, { $value } alındı. +manifest.vars.entry_not_object = Bildirimin `vars` girdisi bir nesne olmalıdır. +manifest.field_not_string = "{ $field }" alanı bir dizge olmalıdır. +manifest.expression.parse_error = { $name } ifadesi ayrıştırılamadı. +manifest.expression.eval_error = { $name } ifadesi değerlendirilemedi. + +# Bildirim makrolarının tanılaması. +manifest.macro.signature_missing_identifier = Makro imzasında tanımlayıcı eksik. +manifest.macro.signature_missing_params = Makro imzasında parametreler eksik. +manifest.macro.compile_failed = { $name } makrosu derlenemedi. +manifest.macro.sequence_invalid = Makrolar, adların şablonlara eşlenmesi biçiminde tanımlanmalıdır. +manifest.macro.register_failed = Bildirimin makroları kaydedilemedi. +manifest.macro.not_initialised = Makro ortamı hazırlanmamış. +manifest.macro.caller_invalid = Makroyu çağıran bir dizge olmalıdır. +manifest.macro.template_load_failed = Makro şablonu yüklenemedi. +manifest.macro.init_failed = Makro ortamı hazırlanamadı. +manifest.macro.missing = { $name } makrosu eksik. + +# Bildirimin glob deseni hataları. +manifest.glob.unmatched_brace = Geçersiz glob deseni "{ $pattern }": { $position }. konumdaki "{ $character }" eşleşmiyor. +manifest.glob.invalid_pattern = Geçersiz glob deseni "{ $pattern }": { $detail }. +manifest.glob.unknown_pattern_error = bilinmeyen desen hatası. +manifest.glob.io_failed = "{ $pattern }" için glob başarısız oldu: { $detail }. +manifest.glob.unknown_io_error = bilinmeyen G/Ç hatası. + +# Ara gösterim hataları. +ir.rule_not_found = "{ $target }" hedefinin başvurduğu "{ $rule }" kuralı bulunamadı. +ir.multiple_rules = "{ $target }" hedefi tek bir kurala başvurmalıdır, { $rules } alındı. +ir.empty_rule = "{ $target }" hedefi bir kurala başvurmalıdır. +ir.duplicate_outputs = Yinelenen çıktılar bulundu: { $outputs }. +ir.circular_dependency = Döngüsel bağımlılık bulundu: { $cycle }. +ir.action_serialisation = Eylem serileştirilemedi: { $details }. +ir.invalid_command = Komutta geçersiz yerleştirme: { $snippet }. + +# Ninja üretimi hataları. +ninja_gen.missing_action = Bir derleme kenarının başvurduğu "{ $id }" eylemi eksik. +ninja_gen.format = Ninja bildiriminin çıktısı biçimlendirilemedi. + +# Makine deseni doğrulaması. +host_pattern.empty = Makine deseni boş olmamalıdır. +host_pattern.contains_scheme = "{ $pattern }" makine deseni bir URL şeması içermemelidir. +host_pattern.contains_slash = "{ $pattern }" makine deseni "/" içermemelidir. +host_pattern.missing_suffix = "{ $pattern }" makine deseni "*." işaretinden sonra bir sonek içermelidir. +host_pattern.empty_label = "{ $pattern }" makine deseni boş bir etiket içeriyor. +host_pattern.invalid_chars = "{ $pattern }" makine deseni geçersiz karakterler içeriyor. +host_pattern.invalid_label_edge = "{ $pattern }" makine deseninin etiketleri "-" ile başlamamalı ya da bitmemelidir. +host_pattern.label_too_long = "{ $pattern }" makine deseni 63 karakterden uzun bir etiket içeriyor. +host_pattern.too_long = "{ $pattern }" makine deseni 255 karakter sınırını aşıyor. + +# Ağ ilkesi. +network_policy.scheme.empty = Şema boş olmamalıdır. +network_policy.scheme.invalid = "{ $scheme }" şeması geçersiz karakterler içeriyor. +network_policy.allowlist.empty = İzin verilen makineler listesi boş olmamalıdır. +network_policy.scheme.not_allowed = "{ $scheme }" şemasına izin verilmiyor. +network_policy.missing_host = URL'de makine adı eksik. +network_policy.host.blocked = "{ $host }" makinesi ilke tarafından engellendi. +network_policy.host.not_allowlisted = "{ $host }" makinesi izin verilenler listesinde değil. + +# Standart kitaplık yapılandırması. +stdlib.config.default_fetch_cache_invalid = Varsayılan fetch önbellek yolu göreli olmalıdır. +stdlib.config.default_which_cache_invalid = Varsayılan which önbellek kapasitesi pozitif olmalıdır. +stdlib.config.workspace_root_absolute = Çalışma alanının kök yolu mutlak olmalıdır. +stdlib.config.fetch_response_limit_positive = fetch yanıt sınırı pozitif olmalıdır. +stdlib.config.command_output_limit_positive = Komut çıktısı yakalama sınırı pozitif olmalıdır. +stdlib.config.command_stream_limit_positive = Komut akış sınırı pozitif olmalıdır. +stdlib.config.which_cache_capacity_positive = which önbellek kapasitesi pozitif olmalıdır. +stdlib.config.skip_dir_empty = Atlanacak dizin girdileri boş olmamalıdır. +stdlib.config.skip_dir_navigation = Atlanacak dizin girdileri ".." içermemelidir. +stdlib.config.skip_dir_separator = Atlanacak dizin girdileri yol ayırıcıları içermemelidir. +stdlib.config.fetch_cache_empty = fetch önbellek yolu boş olmamalıdır. +stdlib.config.fetch_cache_not_relative = fetch önbellek yolu göreli olmalıdır, { $path } alındı. +stdlib.config.fetch_cache_escapes = fetch önbellek yolu çalışma alanının dışına çıkmamalıdır: { $path }. +stdlib.config.open_workspace_root = Geçerli dizin, stdlib çalışma alanının kökü olarak açılamadı. +stdlib.config.resolve_cwd = Geçerli dizin, stdlib çalışma alanının kökü olarak belirlenemedi. +stdlib.config.cwd_non_utf8 = Geçerli dizin UTF-8 olmayan bölümler içeriyor: { $path }. + +# fetch yardımcısının tanılaması. +stdlib.fetch.url_invalid = Geçersiz URL "{ $url }": { $details }. +stdlib.fetch.disallowed = "{ $url }" adresine izin verilmiyor: { $details }. +stdlib.fetch.failed = "{ $url }" adresinden veri alınamadı: { $details }. +stdlib.fetch.cache_read_failed = "{ $name }" önbellek girdisi okunamadı: { $details }. +stdlib.fetch.cache_open_failed = "{ $name }" önbellek girdisi açılamadı: { $details }. +stdlib.fetch.response_read_failed = "{ $url }" adresinden gelen yanıt okunamadı: { $details }. +stdlib.fetch.response_buffer_overflow = "{ $url }" okunurken arabellek taştı. +stdlib.fetch.cache_write_failed = "{ $url }" için önbellek yazılamadı: { $details }. +stdlib.fetch.response_limit_exceeded = "{ $url }" adresinden gelen yanıt { $limit } baytlık sınırı aştı. +stdlib.fetch.cache_limit_exceeded = Önbelleğe alınmış "{ $name }" yanıtı { $limit } baytlık sınırı aştı. +stdlib.fetch.io_failed = "{ $action }" eylemi { $path } için başarısız oldu: { $details }. +stdlib.fetch.action.sync_cache = fetch önbelleğini eşitleme +stdlib.fetch.action.create_cache_dir = fetch önbellek dizinini oluşturma +stdlib.fetch.action.open_cache_dir = fetch önbellek dizinini açma +stdlib.fetch.action.stat_cache = fetch önbellek girdisinin bilgilerini alma +stdlib.fetch.action.open_cache_entry = fetch önbellek girdisini açma + +# Komut yardımcısının tanılaması. +stdlib.command.location = "{ $template }" şablonundaki "{ $command }" komutu +stdlib.command.spawn_failed = { $location } başlatılamadı: { $details }. +stdlib.command.io_failed = { $location } başarısız oldu: { $details }. +stdlib.command.closed_input_early = Komuta yazma tamamlanmadan girdi kapandı. +stdlib.command.broken_pipe = { $location } çalıştırılırken boru hattı koptu: { $details }. +stdlib.command.terminated_by_signal = { $location } bir sinyalle sonlandırıldı. +stdlib.command.exited_with_status = { $location } { $status } durumuyla sona erdi. +stdlib.command.output_limit_exceeded = { $location }, { $stream } için { $limit } baytlık { $mode } sınırını aştı. +stdlib.command.timeout = { $location }, { $seconds } saniyelik zaman sınırını aştı. +stdlib.command.exit_status_suffix = (çıkış durumu { $status }) +stdlib.command.signal_suffix = (sinyalle sonlandırıldı) +stdlib.command.shell.empty = Kabuk komutu boş olmamalıdır. +stdlib.command.grep.empty_pattern = grep deseni boş olmamalıdır. +stdlib.command.grep.flags_not_string = grep bayrakları dizge olmalıdır. +stdlib.command.quote.invalid = { $arg } tırnak içine alınamadı: { $details }. +stdlib.command.quote.line_break = Satır başı ya da satır sonu karakteri içeren bağımsız değişkenler güvenle tırnak içine alınamaz. +stdlib.command.input_undefined = Girdi değeri tanımsız. +stdlib.command.tempfile.root_required = Geçici komut dosyaları oluşturmak için çalışma alanının kökü gereklidir. +stdlib.command.tempfile.create_failed = Geçici komut dosyası oluşturulamadı: { $details }. +stdlib.command.options.invalid_utf8 = Komut seçeneği anahtarı geçerli UTF-8 olmalıdır. +stdlib.command.option.mode_not_string = Çıktı kipi bir dizge olmalıdır. +stdlib.command.options.invalid_type = Komut seçenekleri bir nesne olmalıdır. +stdlib.command.output.mode_unsupported = Desteklenmeyen çıktı kipi: "{ $mode }". +stdlib.command.output.mode.capture = yakalama +stdlib.command.output.mode.streaming = akış +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Yol yardımcısının tanılaması. +stdlib.path.io.failed = "{ $action }" eylemi { $path } için başarısız oldu ({ $label }). +stdlib.path.io.failed_with_detail = "{ $action }" eylemi { $path } için başarısız oldu: { $detail }. +stdlib.path.io.failed_with_label_and_detail = "{ $action }" eylemi { $path } için başarısız oldu ({ $label }): { $detail }. +stdlib.path.io.not_found = bulunamadı +stdlib.path.io.permission_denied = erişim reddedildi +stdlib.path.io.already_exists = zaten var +stdlib.path.io.invalid_input = geçersiz girdi +stdlib.path.io.invalid_data = geçersiz veri +stdlib.path.io.timed_out = süre doldu +stdlib.path.io.interrupted = kesildi +stdlib.path.io.would_block = engellemeye yol açardı +stdlib.path.io.write_zero = sıfır bayt yazıldı +stdlib.path.io.unexpected_eof = beklenmedik dosya sonu +stdlib.path.io.broken_pipe = kopuk boru hattı +stdlib.path.io.connection_refused = bağlantı reddedildi +stdlib.path.io.connection_reset = bağlantı sıfırlandı +stdlib.path.io.connection_aborted = bağlantı kesildi +stdlib.path.io.not_connected = bağlantı yok +stdlib.path.io.addr_in_use = adres kullanımda +stdlib.path.io.addr_not_available = adres kullanılamıyor +stdlib.path.io.out_of_memory = bellek yetersiz +stdlib.path.io.unsupported = desteklenmiyor +stdlib.path.io.file_too_large = dosya çok büyük +stdlib.path.io.resource_busy = kaynak meşgul +stdlib.path.io.executable_busy = çalıştırılabilir dosya meşgul +stdlib.path.io.deadlock = ölümcül kilitlenme +stdlib.path.io.crosses_devices = aygıt sınırını aşıyor +stdlib.path.io.too_many_links = çok fazla bağlantı +stdlib.path.io.invalid_filename = geçersiz dosya adı +stdlib.path.io.arg_list_too_long = bağımsız değişken listesi çok uzun +stdlib.path.io.stale_handle = eskimiş ağ dosyası tanıtıcısı +stdlib.path.io.storage_full = depolama dolu +stdlib.path.io.not_seekable = konumlandırılamaz +stdlib.path.io.network_down = ağ çalışmıyor +stdlib.path.io.network_unreachable = ağa erişilemiyor +stdlib.path.io.host_unreachable = makineye erişilemiyor +stdlib.path.io.other = G/Ç hatası +stdlib.path.action.canonicalize = kurallı biçime çevirme +stdlib.path.action.open_directory = dizin açma +stdlib.path.action.stat = bilgi alma +stdlib.path.action.read = okuma +stdlib.path.action.open_file = dosya açma +stdlib.path.with_suffix.empty_separator = with_suffix boş olmayan bir ayırıcı gerektirir. +stdlib.path.relative_to.mismatch = { $path }, { $root } konumuna göreli değil. +stdlib.path.expanduser.unsupported = ~ işaretinin belirli bir kullanıcı için genişletilmesi desteklenmiyor. +stdlib.path.expanduser.no_home = ~ genişletilemiyor: ev dizinine ilişkin hiçbir ortam değişkeni ayarlı değil. +stdlib.path.contents.unsupported_encoding = Desteklenmeyen kodlama: "{ $encoding }". +stdlib.path.hash.unsupported_algorithm = Desteklenmeyen özet algoritması: "{ $algorithm }". +stdlib.path.hash.unsupported_algorithm_legacy = Desteklenmeyen özet algoritması: "{ $algorithm }" ("{ $feature }" özelliğini etkinleştirin). + +# Koleksiyon yardımcılarının tanılaması. +stdlib.collections.flatten.expected_sequence = flatten dizi öğeleri bekliyordu, ancak { $kind } buldu. +stdlib.collections.group_by.empty_attribute = group_by boş olmayan bir öznitelik gerektirir. +stdlib.collections.group_by.unresolved = group_by, { $kind } türündeki bir öğede "{ $attr }" özniteliğini bulamadı. + +# Zaman yardımcılarının tanılaması. +stdlib.time.offset.invalid = now kayması "{ $offset }" geçersiz: "+HH:MM[:SS]" ya da "Z" bekleniyordu. +stdlib.time.timedelta.overflow = { $component } eklenirken timedelta taştı. +stdlib.time.label.weeks = hafta +stdlib.time.label.days = gün +stdlib.time.label.hours = saat +stdlib.time.label.minutes = dakika +stdlib.time.label.seconds = saniye +stdlib.time.label.milliseconds = milisaniye +stdlib.time.label.microseconds = mikrosaniye +stdlib.time.label.nanoseconds = nanosaniye + +# which yardımcısının tanılaması. +stdlib.which.not_found = [netsuke::jinja::which::not_found] { $count } PATH girdisi denetlendikten sonra "{ $command }" komutu bulunamadı. Önizleme: { $preview } +stdlib.which.not_found.hint.cwd_auto = PATH'in boş bölümleri yok sayılır; çalışma dizinini katmak için cwd_mode="auto" kullanın. +stdlib.which.not_found.hint.cwd_always = Geçerli dizini katmak için cwd_mode="always" ayarlayın. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] "{ $path }" konumundaki "{ $command }" komutu yok ya da çalıştırılabilir değil. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = { $index }. PATH girdisi UTF-8 olmayan karakterler içeriyor; Netsuke UTF-8 yollar gerektirir. +stdlib.which.command.empty = which boş olmayan bir dizge gerektirir. +stdlib.which.cwd_mode.invalid = cwd_mode "auto", "always" ya da "never" olmalıdır, "{ $mode }" alındı. +stdlib.which.cwd.resolve_failed = Geçerli dizin belirlenemedi: { $details }. +stdlib.which.cwd.non_utf8 = Geçerli dizin UTF-8 olmayan bölümler içeriyor. +stdlib.which.canonicalize_failed = "{ $path }" kurallı biçime çevrilemedi: { $details }. +stdlib.which.is_executable = "{ $path }" öğesinin çalıştırılabilir olup olmadığı belirlenemedi: { $details }. +stdlib.which.canonicalize_non_utf8 = Kurallı yol UTF-8 olmayan bölümler içeriyor. +stdlib.which.workspace_non_utf8 = "{ $command }" komutu çözümlenirken çalışma alanı yolu UTF-8 olmayan bölümler içeriyor: { $path }. +stdlib.which.walkdir_error = Komut çözümlenirken çalışma alanı gezilirken hata oluştu: { $details }. + +# Standart kitaplığın kaydı. +stdlib.register.open_dir = stdlib kaydı için geçerli dizin açılamadı. +stdlib.register.resolve_dir = stdlib kaydı için geçerli dizin belirlenemedi. +stdlib.register.dir_non_utf8 = Geçerli dizin UTF-8 olmayan bölümler içeriyor: { $path }. + +# Erişilebilir çıktı kipinde durum bildirimi. +status.state.pending = bekliyor +status.state.running = sürüyor +status.state.done = bitti +status.state.failed = başarısız +status.stage.label = { $current }/{ $total }. aşama: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = { $current }/{ $total }. görev +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Bildirim dosyası okunuyor +status.stage.initial_yaml_parsing = YAML belgesi ayrıştırılıyor +status.stage.template_expansion = Şablon yönergeleri genişletiliyor +status.stage.final_rendering = Bildirim değerleri geri çözülüp işleniyor +status.stage.ir_generation_validation = Bağımlılık çizgesi oluşturuluyor ve doğrulanıyor +status.stage.ninja_synthesis = Ninja derleme planı hazırlanıyor +status.stage.ninja_synthesis_execute = Ninja planı hazırlanıyor ve { $tool } çalıştırılıyor +status.stage.graph_rendering = Çizge ürünü işleniyor +status.stage.graph_rendering_with_tool = { $tool } işleniyor +status.complete = { $tool } tamamlandı. +status.timing.summary_header = Aşamalara göre süre özeti: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Toplam işlem hattı süresi: { $duration } +status.tool.build = Derleme +status.tool.clean = Temizleme +status.tool.graph = Çizge +status.tool.graph_html = Çizge (HTML) +status.tool.generate = Üretme + +# Çizgenin HTML gösterimindeki metinler. +graph.html.title = Netsuke derleme çizgesi +graph.html.heading = Netsuke derleme çizgesi +graph.html.description = Netsuke tarafından işlenen derleme çizgesi +graph.html.outline.summary = Hedefler ve bağımlılıklar (metin taslağı) +graph.html.outline.no_inputs = Girdi yok +graph.html.noscript.notice = JavaScript kapalı. Yukarıdaki metin taslağı çizgenin tamamıdır; DOT kaynağı aşağıda yer alır. + +# Erişilebilir çıktı için anlamsal önekler. +semantic.prefix.error = Hata: +semantic.prefix.warning = Uyarı: +semantic.prefix.success = Başarılı: +semantic.prefix.info = Bilgi: +semantic.prefix.timing = Süre: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Çevirmenler için çoğul biçim örnekleri. +# Türkçede sayıdan sonra ad tekil kalır, bu yüzden CLDR yalnızca `one` ve +# `other` kategorilerini kullanır ve her ikisi de aynı biçimi alır. +example.files_processed = { $count -> + [one] { $count } dosya işlendi. + *[other] { $count } dosya işlendi. +} + +example.errors_found = { $count -> + [0] Hata bulunmadı. + [one] { $count } hata bulundu. + *[other] { $count } hata bulundu. +} diff --git a/locales/uk/messages.ftl b/locales/uk/messages.ftl new file mode 100644 index 000000000..2e62a77fd --- /dev/null +++ b/locales/uk/messages.ftl @@ -0,0 +1,404 @@ +# Ресурси локалізації командного рядка Netsuke. + +cli.about = Netsuke компілює маніфести YAML + Jinja у плани збирання Ninja. +cli.long_about = Netsuke перетворює маніфести YAML + Jinja на відтворювані графи Ninja й запускає Ninja з безпечними типовими значеннями. +cli.usage = { $usage } + +# Текст довідки для загальних параметрів. +cli.flag.file.help = Шлях до файлу маніфесту Netsuke, який слід використати. +cli.flag.directory.help = Виконати так, ніби запуск відбувся в цьому каталозі. +cli.flag.config.help = Шлях до файлу конфігурації в обхід автоматичного пошуку. +cli.flag.jobs.help = Задати кількість паралельних завдань збирання. +cli.flag.verbose.help = Увімкнути докладне діагностичне журналювання та підсумки часу після завершення. +cli.flag.locale.help = Мовна мітка для текстів командного рядка (наприклад: en-US, uk). +cli.flag.fetch_allow_scheme.help = Додаткові схеми URL, дозволені для помічника fetch. +cli.flag.fetch_allow_host.help = Назви вузлів, дозволені за увімкненої типової заборони. +cli.flag.fetch_block_host.help = Назви вузлів, які блокуються завжди, навіть якщо дозволені деінде. +cli.flag.fetch_default_deny.help = Типово забороняти всі вузли; дозволяти лише оголошений перелік. +cli.flag.json.help = Виводити машиночитний JSON. +cli.flag.no_input.help = Ніколи не читати інтерактивне введення. +cli.flag.color.help = Політика кольорового виводу (auto, always, never). +cli.flag.emoji.help = Політика використання емодзі (auto, always, never). +cli.flag.progress.help = Політика показу поступу (auto, always, never). +cli.flag.accessibility.help = Політика доступного виводу (auto, on, off). +cli.flag.default_targets.help = Типові цілі збирання, коли не вказано жодної. + +# Описи підкоманд. +cli.subcommand.build.about = Зібрати цілі, визначені в маніфесті (типово). +cli.subcommand.build.long_about = Зібрати запитані цілі; якщо жодної не вказано, узяти типові цілі маніфесту. +cli.subcommand.clean.about = Видалити артефакти збирання засобами Ninja. +cli.subcommand.clean.long_about = Створити тимчасовий файл Ninja, а потім виконати `ninja -t clean`. +cli.subcommand.graph.about = Вивести граф залежностей збирання. Типовий формат — DOT. +cli.subcommand.graph.long_about = Перетворити розібраний маніфест Netsuke на канонічний граф збирання та записати його у форматі Graphviz DOT або, з параметром `--html`, як самостійну сторінку HTML. Використайте `--output <ФАЙЛ>`, щоб записати у файл; `-` виводить у стандартний потік. +cli.subcommand.generate.about = Створити маніфест Ninja, не запускаючи Ninja. +cli.subcommand.generate.long_about = Записати створений маніфест Ninja у стандартний потік виводу або у файл, вибраний параметром `--output`. + +# Текст довідки для параметрів підкоманди build. +cli.subcommand.build.flag.targets.help = Цілі для збирання (якщо не вказано, беруться типові цілі маніфесту). + +# Текст довідки для параметрів підкоманди graph. +cli.subcommand.graph.flag.html.help = Показати граф як самостійну сторінку HTML замість формату DOT. +cli.subcommand.graph.flag.output.help = Записати артефакт графа у ФАЙЛ; для стандартного потоку використайте `-`. + +# Текст довідки для параметрів підкоманди generate. +cli.subcommand.generate.flag.output.help = Записати створений маніфест Ninja у ФАЙЛ замість стандартного потоку виводу. + +# Помилки перевірки в командному рядку. +cli.validation.jobs.invalid_number = { $value } не є припустимим числом. +cli.validation.jobs.out_of_range = Кількість завдань має бути в межах від { $min } до { $max }. +cli.validation.scheme.empty = Схема не повинна бути порожньою. +cli.validation.scheme.invalid_start = Схема «{ $scheme }» має починатися з літери ASCII. +cli.validation.scheme.invalid = Неприпустима схема «{ $scheme }». +cli.validation.locale.empty = Мовна мітка не повинна бути порожньою. +cli.validation.locale.invalid = Неприпустима мовна мітка «{ $locale }». +cli.validation.color.invalid = Неприпустима політика кольору «{ $value }». Припустимі значення: auto, always, never. +cli.validation.emoji.invalid = Неприпустима політика емодзі «{ $value }». Припустимі значення: auto, always, never. +cli.validation.progress.invalid = Неприпустима політика поступу «{ $value }». Припустимі значення: auto, always, never. +cli.validation.accessibility.invalid = Неприпустима політика доступності «{ $value }». Припустимі значення: auto, on, off. +cli.validation.config.expected_object = Значення командного рядка мали серіалізуватися в об’єкт, отримано { $value }. + +# Повідомлення про помилки від Clap. +clap-error-missing-argument = Відсутній обов’язковий аргумент: { $argument } +clap-error-missing-subcommand = Відсутня підкоманда. Доступні варіанти: { $valid_subcommands } +clap-error-unknown-argument = Невідомий аргумент: { $argument } +clap-error-invalid-value = Неприпустиме значення для { $argument }: { $value } +clap-error-invalid-subcommand = Невідома підкоманда: { $subcommand } +# Примітка: формулювання value-validation відрізняється від invalid-value, щоб +# відрізняти помилки власних перевіряльників (ErrorKind::ValueValidation) від +# невідповідності типів (ErrorKind::InvalidValue). +clap-error-value-validation = Перевірку не пройдено для { $argument }: { $value } + +# Помилки та контекст виконання. +runner.manifest.not_found = Маніфест «{ $manifest_name }» не знайдено в каталозі { $directory }. +runner.manifest.not_found.help = Переконайтеся, що маніфест існує, або вкажіть `--file` з правильним шляхом. +runner.manifest.path_missing_name = У шляху до маніфесту «{ $path }» немає імені файлу. +runner.manifest.path_utf8 = Шлях до маніфесту «{ $path }» не є коректним UTF-8. +runner.manifest.directory_utf8 = Шлях до каталогу маніфесту «{ $path }» не є коректним UTF-8. +runner.manifest.directory_label = каталог `{ $directory }` +runner.manifest.current_directory_label = поточний каталог +runner.context.network_policy = Не вдалося побудувати мережеву політику. +runner.context.load_manifest = Не вдалося завантажити маніфест за шляхом { $path }. +runner.context.serialise_manifest = Не вдалося серіалізувати маніфест. +runner.context.build_graph = Не вдалося побудувати граф за маніфестом. +runner.context.generate_ninja = Не вдалося створити маніфест Ninja. +runner.context.render_graph = Не вдалося відобразити артефакт графа. + +runner.io.create_temp_file = Не вдалося створити тимчасовий файл Ninja. +runner.io.write_temp_ninja = Не вдалося записати тимчасовий файл Ninja. +runner.io.flush_temp_ninja = Не вдалося скинути буфер тимчасового файлу Ninja. +runner.io.sync_temp_ninja = Не вдалося синхронізувати тимчасовий файл Ninja. +runner.io.create_parent_dir = Не вдалося створити батьківський каталог { $path }. +runner.io.create_ninja_file = Не вдалося створити файл Ninja у { $path }. +runner.io.write_ninja_file = Не вдалося записати файл Ninja у { $path }. +runner.io.flush_ninja_file = Не вдалося скинути буфер файлу Ninja у { $path }. +runner.io.sync_ninja_file = Не вдалося синхронізувати файл Ninja у { $path }. +runner.io.open_ambient_dir = Не вдалося відкрити навколишній каталог. +runner.io.no_existing_ancestor = Для { $path } не існує батьківського каталогу. +runner.io.derive_relative_path = Не вдалося вивести відносний шлях Ninja. +runner.io.non_utf8_path = Шляхи, відмінні від UTF-8, не підтримуються (шлях: { $path }). +runner.io.write_stdout = Не вдалося записати маніфест Ninja у стандартний потік виводу. +runner.io.flush_stdout = Не вдалося скинути буфер стандартного потоку виводу. + +# Діагностика маніфесту. +manifest.parse = Не вдалося розібрати маніфест. +manifest.structure_error = Помилка структури маніфесту в { $name }: { $details } +manifest.yaml.parse = Помилка розбору YAML у рядку { $line }, стовпці { $column }: { $details } +manifest.yaml.label = некоректний YAML +manifest.yaml.hint.tabs = YAML не допускає табуляції; для відступів використовуйте пробіли. +manifest.yaml.hint.list_item = Елементи списку YAML мають починатися з «-» і мати правильний відступ. +manifest.yaml.hint.expected_colon = Схоже на елемент відображення; після ключа бракує «:». +manifest.yaml.hint.mapping_values = Відображення YAML потребують значення після «:» (або вкладеного блоку). +manifest.yaml.hint.invalid_token = Лексема YAML некоректна або несподівана. +manifest.yaml.hint.escape = Екрануйте зворотні скісні риски або вилучіть некоректні escape-послідовності. +manifest.env.missing = Обов’язкову змінну середовища «{ $name }» не задано. +manifest.env.invalid_utf8 = Змінна середовища «{ $name }» містить некоректний UTF-8. +manifest.vars.not_object = Поле `vars` маніфесту має бути відображенням або об’єктом. +manifest.read_failed = Не вдалося прочитати маніфест за шляхом { $path }. +manifest.resolve_workspace_root = Не вдалося визначити корінь робочої області. +manifest.workspace_non_utf8 = Кореневий шлях робочої області «{ $path }» не є коректним UTF-8. +manifest.path_non_utf8 = Шлях маніфесту «{ $manifest }» не є коректним UTF-8: { $path }. +manifest.path_missing_name = У шляху до маніфесту «{ $path }» немає імені файлу. +manifest.open_workspace_failed = Не вдалося відкрити робочу область { $workspace } для маніфесту { $manifest }. +manifest.foreach.not_iterable = Вираз `foreach` не є ітерованим. +manifest.foreach.serialise_item = Не вдалося серіалізувати елемент `foreach`. +manifest.when.empty = Вираз `when` не повинен бути порожнім. +manifest.when.eval_error = Не вдалося обчислити вираз `when` «{ $expr }». +manifest.when.template_error = Не вдалося відобразити шаблон `when` «{ $expr }». +manifest.target.vars_not_object = Поле `vars` цілі має бути об’єктом, отримано { $value }. +manifest.vars.entry_not_object = Запис `vars` маніфесту має бути об’єктом. +manifest.field_not_string = Поле «{ $field }» має бути рядком. +manifest.expression.parse_error = Не вдалося розібрати вираз { $name }. +manifest.expression.eval_error = Не вдалося обчислити вираз { $name }. + +# Діагностика макросів маніфесту. +manifest.macro.signature_missing_identifier = У сигнатурі макроса відсутній ідентифікатор. +manifest.macro.signature_missing_params = У сигнатурі макроса відсутні параметри. +manifest.macro.compile_failed = Не вдалося скомпілювати макрос { $name }. +manifest.macro.sequence_invalid = Макроси мають задаватися як відображення імен на шаблони. +manifest.macro.register_failed = Не вдалося зареєструвати макроси маніфесту. +manifest.macro.not_initialised = Середовище макросів не ініціалізовано. +manifest.macro.caller_invalid = Викликач макроса має бути рядком. +manifest.macro.template_load_failed = Не вдалося завантажити шаблон макроса. +manifest.macro.init_failed = Не вдалося ініціалізувати середовище макросів. +manifest.macro.missing = Макрос { $name } відсутній. + +# Помилки шаблонів glob у маніфесті. +manifest.glob.unmatched_brace = Некоректний шаблон glob «{ $pattern }»: «{ $character }» без пари в позиції { $position }. +manifest.glob.invalid_pattern = Некоректний шаблон glob «{ $pattern }»: { $detail }. +manifest.glob.unknown_pattern_error = невідома помилка шаблону. +manifest.glob.io_failed = Збій glob для «{ $pattern }»: { $detail }. +manifest.glob.unknown_io_error = невідома помилка вводу-виводу. + +# Помилки проміжного подання. +ir.rule_not_found = Правило «{ $rule }», на яке посилається ціль «{ $target }», не знайдено. +ir.multiple_rules = Ціль «{ $target }» має посилатися рівно на одне правило, отримано { $rules }. +ir.empty_rule = Ціль «{ $target }» має посилатися на правило. +ir.duplicate_outputs = Виявлено повторювані вихідні файли: { $outputs }. +ir.circular_dependency = Виявлено циклічну залежність: { $cycle }. +ir.action_serialisation = Не вдалося серіалізувати дію: { $details }. +ir.invalid_command = Некоректна підстановка в команді: { $snippet }. + +# Помилки створення файлів Ninja. +ninja_gen.missing_action = Відсутня дія «{ $id }», на яку посилається ребро збирання. +ninja_gen.format = Не вдалося відформатувати вивід маніфесту Ninja. + +# Перевірка шаблонів вузлів. +host_pattern.empty = Шаблон вузла не повинен бути порожнім. +host_pattern.contains_scheme = Шаблон вузла «{ $pattern }» не повинен містити схему URL. +host_pattern.contains_slash = Шаблон вузла «{ $pattern }» не повинен містити «/». +host_pattern.missing_suffix = Шаблон вузла «{ $pattern }» має містити суфікс після «*.». +host_pattern.empty_label = Шаблон вузла «{ $pattern }» містить порожню мітку. +host_pattern.invalid_chars = Шаблон вузла «{ $pattern }» містить неприпустимі символи. +host_pattern.invalid_label_edge = Мітки шаблону вузла «{ $pattern }» не повинні починатися чи закінчуватися символом «-». +host_pattern.label_too_long = Шаблон вузла «{ $pattern }» містить мітку, довшу за 63 символи. +host_pattern.too_long = Шаблон вузла «{ $pattern }» перевищує обмеження у 255 символів. + +# Мережева політика. +network_policy.scheme.empty = Схема не повинна бути порожньою. +network_policy.scheme.invalid = Схема «{ $scheme }» містить неприпустимі символи. +network_policy.allowlist.empty = Перелік дозволених вузлів не повинен бути порожнім. +network_policy.scheme.not_allowed = Схема «{ $scheme }» не дозволена. +network_policy.missing_host = В URL відсутній вузол. +network_policy.host.blocked = Вузол «{ $host }» заблоковано політикою. +network_policy.host.not_allowlisted = Вузла «{ $host }» немає в переліку дозволених. + +# Конфігурація стандартної бібліотеки. +stdlib.config.default_fetch_cache_invalid = Типовий шлях кешу fetch має бути відносним. +stdlib.config.default_which_cache_invalid = Типова місткість кешу which має бути додатною. +stdlib.config.workspace_root_absolute = Кореневий шлях робочої області має бути абсолютним. +stdlib.config.fetch_response_limit_positive = Обмеження на відповідь fetch має бути додатним. +stdlib.config.command_output_limit_positive = Обмеження на перехоплений вивід команд має бути додатним. +stdlib.config.command_stream_limit_positive = Обмеження на потік команд має бути додатним. +stdlib.config.which_cache_capacity_positive = Місткість кешу which має бути додатною. +stdlib.config.skip_dir_empty = Записи пропущених каталогів не повинні бути порожніми. +stdlib.config.skip_dir_navigation = Записи пропущених каталогів не повинні містити «..». +stdlib.config.skip_dir_separator = Записи пропущених каталогів не повинні містити роздільники шляху. +stdlib.config.fetch_cache_empty = Шлях кешу fetch не повинен бути порожнім. +stdlib.config.fetch_cache_not_relative = Шлях кешу fetch має бути відносним, отримано { $path }. +stdlib.config.fetch_cache_escapes = Шлях кешу fetch не повинен виходити за межі робочої області: { $path }. +stdlib.config.open_workspace_root = Не вдалося відкрити поточний каталог як корінь робочої області stdlib. +stdlib.config.resolve_cwd = Не вдалося визначити поточний каталог як корінь робочої області stdlib. +stdlib.config.cwd_non_utf8 = Поточний каталог містить частини, які не є UTF-8: { $path }. + +# Діагностика помічника fetch. +stdlib.fetch.url_invalid = Некоректний URL «{ $url }»: { $details }. +stdlib.fetch.disallowed = URL «{ $url }» не дозволено: { $details }. +stdlib.fetch.failed = Не вдалося завантажити «{ $url }»: { $details }. +stdlib.fetch.cache_read_failed = Не вдалося прочитати запис кешу «{ $name }»: { $details }. +stdlib.fetch.cache_open_failed = Не вдалося відкрити запис кешу «{ $name }»: { $details }. +stdlib.fetch.response_read_failed = Не вдалося прочитати відповідь від «{ $url }»: { $details }. +stdlib.fetch.response_buffer_overflow = Переповнення буфера під час читання «{ $url }». +stdlib.fetch.cache_write_failed = Не вдалося записати кеш для «{ $url }»: { $details }. +stdlib.fetch.response_limit_exceeded = Відповідь від «{ $url }» перевищила обмеження у { $limit } байтів. +stdlib.fetch.cache_limit_exceeded = Кешована відповідь «{ $name }» перевищила обмеження у { $limit } байтів. +stdlib.fetch.io_failed = Не вдалося виконати дію «{ $action }» для { $path }: { $details }. +stdlib.fetch.action.sync_cache = синхронізація кешу fetch +stdlib.fetch.action.create_cache_dir = створення каталогу кешу fetch +stdlib.fetch.action.open_cache_dir = відкриття каталогу кешу fetch +stdlib.fetch.action.stat_cache = отримання відомостей про запис кешу fetch +stdlib.fetch.action.open_cache_entry = відкриття запису кешу fetch + +# Діагностика помічника для команд. +stdlib.command.location = команда «{ $command }» у шаблоні «{ $template }» +stdlib.command.spawn_failed = { $location } не запустилася: { $details }. +stdlib.command.io_failed = { $location } зазнала збою: { $details }. +stdlib.command.closed_input_early = Введення закрилося до завершення запису в команду. +stdlib.command.broken_pipe = Розірвано канал, поки виконувалася { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } завершена сигналом. +stdlib.command.exited_with_status = { $location } завершилася з кодом { $status }. +stdlib.command.output_limit_exceeded = { $location } перевищила обмеження режиму «{ $mode }» у { $limit } байтів для { $stream }. +stdlib.command.timeout = { $location } перевищила граничний час у { $seconds } с. +stdlib.command.exit_status_suffix = (код завершення { $status }) +stdlib.command.signal_suffix = (завершено сигналом) +stdlib.command.shell.empty = Команда оболонки не повинна бути порожньою. +stdlib.command.grep.empty_pattern = Шаблон grep не повинен бути порожнім. +stdlib.command.grep.flags_not_string = Прапорці grep мають бути рядками. +stdlib.command.quote.invalid = Не вдалося взяти { $arg } у лапки: { $details }. +stdlib.command.quote.line_break = Аргументи з поверненням каретки чи переведенням рядка не можна безпечно взяти в лапки. +stdlib.command.input_undefined = Вхідне значення не визначено. +stdlib.command.tempfile.root_required = Для створення тимчасових файлів команд потрібен корінь робочої області. +stdlib.command.tempfile.create_failed = Не вдалося створити тимчасовий файл команди: { $details }. +stdlib.command.options.invalid_utf8 = Ключ параметра команди має бути коректним UTF-8. +stdlib.command.option.mode_not_string = Режим виводу має бути рядком. +stdlib.command.options.invalid_type = Параметри команди мають бути об’єктом. +stdlib.command.output.mode_unsupported = Непідтримуваний режим виводу «{ $mode }». +stdlib.command.output.mode.capture = перехоплення +stdlib.command.output.mode.streaming = потокова передача +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Діагностика помічника для шляхів. +stdlib.path.io.failed = Не вдалося виконати дію «{ $action }» для { $path } ({ $label }). +stdlib.path.io.failed_with_detail = Не вдалося виконати дію «{ $action }» для { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = Не вдалося виконати дію «{ $action }» для { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = не знайдено +stdlib.path.io.permission_denied = доступ заборонено +stdlib.path.io.already_exists = вже існує +stdlib.path.io.invalid_input = некоректне введення +stdlib.path.io.invalid_data = некоректні дані +stdlib.path.io.timed_out = час очікування минув +stdlib.path.io.interrupted = перервано +stdlib.path.io.would_block = призвело б до блокування +stdlib.path.io.write_zero = записано нуль байтів +stdlib.path.io.unexpected_eof = несподіваний кінець файлу +stdlib.path.io.broken_pipe = розірваний канал +stdlib.path.io.connection_refused = у з’єднанні відмовлено +stdlib.path.io.connection_reset = з’єднання скинуто +stdlib.path.io.connection_aborted = з’єднання перервано +stdlib.path.io.not_connected = немає з’єднання +stdlib.path.io.addr_in_use = адреса вже використовується +stdlib.path.io.addr_not_available = адреса недоступна +stdlib.path.io.out_of_memory = бракує пам’яті +stdlib.path.io.unsupported = не підтримується +stdlib.path.io.file_too_large = файл завеликий +stdlib.path.io.resource_busy = ресурс зайнятий +stdlib.path.io.executable_busy = виконуваний файл зайнятий +stdlib.path.io.deadlock = взаємне блокування +stdlib.path.io.crosses_devices = перетинає межу пристроїв +stdlib.path.io.too_many_links = забагато посилань +stdlib.path.io.invalid_filename = некоректне ім’я файлу +stdlib.path.io.arg_list_too_long = завеликий перелік аргументів +stdlib.path.io.stale_handle = застарілий дескриптор мережевого файлу +stdlib.path.io.storage_full = сховище заповнено +stdlib.path.io.not_seekable = позиціювання недоступне +stdlib.path.io.network_down = мережа не працює +stdlib.path.io.network_unreachable = мережа недосяжна +stdlib.path.io.host_unreachable = вузол недосяжний +stdlib.path.io.other = помилка вводу-виводу +stdlib.path.action.canonicalize = канонізація +stdlib.path.action.open_directory = відкриття каталогу +stdlib.path.action.stat = отримання відомостей +stdlib.path.action.read = читання +stdlib.path.action.open_file = відкриття файлу +stdlib.path.with_suffix.empty_separator = with_suffix потребує непорожнього роздільника. +stdlib.path.relative_to.mismatch = { $path } не є відносним до { $root }. +stdlib.path.expanduser.unsupported = Розкриття ~ для конкретного користувача не підтримується. +stdlib.path.expanduser.no_home = Не вдається розкрити ~: не задано жодної змінної середовища домашнього каталогу. +stdlib.path.contents.unsupported_encoding = Непідтримуване кодування «{ $encoding }». +stdlib.path.hash.unsupported_algorithm = Непідтримуваний алгоритм хешування «{ $algorithm }». +stdlib.path.hash.unsupported_algorithm_legacy = Непідтримуваний алгоритм хешування «{ $algorithm }» (увімкніть можливість «{ $feature }»). + +# Діагностика помічників для колекцій. +stdlib.collections.flatten.expected_sequence = flatten очікував елементи послідовності, але знайшов { $kind }. +stdlib.collections.group_by.empty_attribute = group_by потребує непорожнього атрибута. +stdlib.collections.group_by.unresolved = group_by не зміг знайти «{ $attr }» в елементі типу { $kind }. + +# Діагностика помічників для часу. +stdlib.time.offset.invalid = Зсув now «{ $offset }» некоректний: очікувалося «+HH:MM[:SS]» або «Z». +stdlib.time.timedelta.overflow = Переповнення timedelta під час додавання компонента { $component }. +stdlib.time.label.weeks = тижні +stdlib.time.label.days = дні +stdlib.time.label.hours = години +stdlib.time.label.minutes = хвилини +stdlib.time.label.seconds = секунди +stdlib.time.label.milliseconds = мілісекунди +stdlib.time.label.microseconds = мікросекунди +stdlib.time.label.nanoseconds = наносекунди + +# Діагностика помічника which. +stdlib.which.not_found = [netsuke::jinja::which::not_found] команду «{ $command }» не знайдено після перевірки { $count } записів PATH. Попередній перегляд: { $preview } +stdlib.which.not_found.hint.cwd_auto = Порожні сегменти PATH ігноруються; задайте cwd_mode="auto", щоб урахувати робочий каталог. +stdlib.which.not_found.hint.cwd_always = Задайте cwd_mode="always", щоб урахувати поточний каталог. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] команда «{ $command }» за шляхом «{ $path }» відсутня або не є виконуваною. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = <порожньо> +stdlib.which.path_entry.non_utf8 = Запис PATH № { $index } містить символи, які не є UTF-8; Netsuke потребує шляхів у UTF-8. +stdlib.which.command.empty = which потребує непорожнього рядка. +stdlib.which.cwd_mode.invalid = cwd_mode має бути «auto», «always» або «never», отримано «{ $mode }». +stdlib.which.cwd.resolve_failed = Не вдалося визначити поточний каталог: { $details }. +stdlib.which.cwd.non_utf8 = Поточний каталог містить частини, які не є UTF-8. +stdlib.which.canonicalize_failed = Не вдалося канонізувати «{ $path }»: { $details }. +stdlib.which.is_executable = Не вдалося перевірити, чи є «{ $path }» виконуваним: { $details }. +stdlib.which.canonicalize_non_utf8 = Канонічний шлях містить частини, які не є UTF-8. +stdlib.which.workspace_non_utf8 = Шлях робочої області містить частини, які не є UTF-8, під час пошуку команди «{ $command }»: { $path }. +stdlib.which.walkdir_error = Помилка обходу робочої області під час пошуку команди: { $details }. + +# Реєстрація стандартної бібліотеки. +stdlib.register.open_dir = Не вдалося відкрити поточний каталог для реєстрації stdlib. +stdlib.register.resolve_dir = Не вдалося визначити поточний каталог для реєстрації stdlib. +stdlib.register.dir_non_utf8 = Поточний каталог містить частини, які не є UTF-8: { $path }. + +# Звіт про стан у доступному режимі виводу. +status.state.pending = очікує +status.state.running = виконується +status.state.done = готово +status.state.failed = збій +status.stage.label = Етап { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Завдання { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Читання файлу маніфесту +status.stage.initial_yaml_parsing = Розбір документа YAML +status.stage.template_expansion = Розкриття директив шаблону +status.stage.final_rendering = Десеріалізація та відображення значень маніфесту +status.stage.ir_generation_validation = Побудова та перевірка графа залежностей +status.stage.ninja_synthesis = Побудова плану збирання Ninja +status.stage.ninja_synthesis_execute = Побудова плану Ninja та запуск { $tool } +status.stage.graph_rendering = Відображення артефакта графа +status.stage.graph_rendering_with_tool = Відображення { $tool } +status.complete = { $tool }: завершено. +status.timing.summary_header = Підсумок часу за етапами: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Загальний час конвеєра: { $duration } +status.tool.build = Збирання +status.tool.clean = Очищення +status.tool.graph = Граф +status.tool.graph_html = Граф (HTML) +status.tool.generate = Генерація + +# Рядки HTML-подання графа. +graph.html.title = Граф збирання Netsuke +graph.html.heading = Граф збирання Netsuke +graph.html.description = Граф збирання, відображений Netsuke +graph.html.outline.summary = Цілі та залежності (текстова структура) +graph.html.outline.no_inputs = Немає вхідних даних +graph.html.noscript.notice = JavaScript вимкнено. Текстова структура вище містить увесь граф; нижче наведено вихідний код DOT. + +# Семантичні префікси доступного виводу. +semantic.prefix.error = Помилка: +semantic.prefix.warning = Попередження: +semantic.prefix.success = Успішно: +semantic.prefix.info = Відомості: +semantic.prefix.timing = Час: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Приклади форм множини для перекладачів. +# Українська використовує категорії CLDR `one`, `few`, `many` та `other`. +# Цілі числа розподіляються так: `one` — 1, 21, 31…, `few` — 2–4, 22–24…, +# `many` — 0, 5–20, 25–30… Категорія `other` стосується дробових значень, +# тому вона ж є варіантом за замовчуванням. +example.files_processed = { $count -> + [one] Оброблено { $count } файл. + [few] Оброблено { $count } файли. + [many] Оброблено { $count } файлів. + *[other] Оброблено { $count } файла. +} + +example.errors_found = { $count -> + [0] Помилок не знайдено. + [one] Знайдено { $count } помилку. + [few] Знайдено { $count } помилки. + [many] Знайдено { $count } помилок. + *[other] Знайдено { $count } помилки. +} diff --git a/locales/vi/messages.ftl b/locales/vi/messages.ftl new file mode 100644 index 000000000..daaafe505 --- /dev/null +++ b/locales/vi/messages.ftl @@ -0,0 +1,395 @@ +# Tài nguyên bản địa hoá cho giao diện dòng lệnh Netsuke. + +cli.about = Netsuke biên dịch tệp kê khai YAML + Jinja thành kế hoạch dựng Ninja. +cli.long_about = Netsuke chuyển tệp kê khai YAML + Jinja thành đồ thị Ninja có thể tái lập rồi chạy Ninja với các giá trị mặc định an toàn. +cli.usage = { $usage } + +# Văn bản trợ giúp cho các tuỳ chọn chung. +cli.flag.file.help = Đường dẫn tới tệp kê khai Netsuke cần dùng. +cli.flag.directory.help = Chạy như thể đã khởi động trong thư mục này. +cli.flag.config.help = Đường dẫn tới tệp cấu hình, bỏ qua việc tìm kiếm tự động. +cli.flag.jobs.help = Đặt số lượng tác vụ dựng chạy song song. +cli.flag.verbose.help = Bật nhật ký chẩn đoán chi tiết và bản tóm tắt thời gian khi hoàn tất. +cli.flag.locale.help = Thẻ ngôn ngữ cho văn bản dòng lệnh (ví dụ: en-US, vi). +cli.flag.fetch_allow_scheme.help = Các lược đồ URL bổ sung được phép cho hàm trợ giúp fetch. +cli.flag.fetch_allow_host.help = Tên máy chủ được phép khi bật chế độ từ chối mặc định. +cli.flag.fetch_block_host.help = Tên máy chủ luôn bị chặn, kể cả khi được phép ở nơi khác. +cli.flag.fetch_default_deny.help = Mặc định từ chối mọi máy chủ; chỉ cho phép danh sách đã khai báo. +cli.flag.json.help = Xuất dữ liệu JSON máy đọc được. +cli.flag.no_input.help = Không bao giờ đọc dữ liệu nhập tương tác. +cli.flag.color.help = Chính sách xuất màu (auto, always, never). +cli.flag.emoji.help = Chính sách biểu tượng cảm xúc (auto, always, never). +cli.flag.progress.help = Chính sách hiển thị tiến trình (auto, always, never). +cli.flag.accessibility.help = Chính sách xuất dữ liệu dễ tiếp cận (auto, on, off). +cli.flag.default_targets.help = Đích dựng mặc định khi không chỉ định đích nào. + +# Mô tả các lệnh con. +cli.subcommand.build.about = Dựng các đích được khai báo trong tệp kê khai (mặc định). +cli.subcommand.build.long_about = Dựng các đích được yêu cầu; nếu không có đích nào, dùng các đích mặc định của tệp kê khai. +cli.subcommand.clean.about = Xoá sản phẩm dựng thông qua Ninja. +cli.subcommand.clean.long_about = Tạo một tệp Ninja tạm rồi chạy `ninja -t clean`. +cli.subcommand.graph.about = Xuất đồ thị phụ thuộc của quá trình dựng. Định dạng mặc định là DOT. +cli.subcommand.graph.long_about = Chiếu tệp kê khai Netsuke đã phân tích thành đồ thị dựng chuẩn tắc rồi ghi ở định dạng Graphviz DOT, hoặc thành trang HTML độc lập với `--html`. Dùng `--output ` để ghi ra tệp; `-` ghi ra đầu ra chuẩn. +cli.subcommand.generate.about = Tạo tệp kê khai Ninja mà không chạy Ninja. +cli.subcommand.generate.long_about = Ghi tệp kê khai Ninja đã tạo ra đầu ra chuẩn hoặc ra tệp được chọn bằng `--output`. + +# Văn bản trợ giúp cho tuỳ chọn của lệnh con build. +cli.subcommand.build.flag.targets.help = Các đích cần dựng (nếu bỏ trống sẽ dùng đích mặc định của tệp kê khai). + +# Văn bản trợ giúp cho tuỳ chọn của lệnh con graph. +cli.subcommand.graph.flag.html.help = Kết xuất đồ thị thành trang HTML độc lập thay cho định dạng DOT. +cli.subcommand.graph.flag.output.help = Ghi sản phẩm đồ thị ra TỆP; dùng `-` cho đầu ra chuẩn. + +# Văn bản trợ giúp cho tuỳ chọn của lệnh con generate. +cli.subcommand.generate.flag.output.help = Ghi tệp kê khai Ninja đã tạo ra TỆP thay vì đầu ra chuẩn. + +# Lỗi kiểm tra ở dòng lệnh. +cli.validation.jobs.invalid_number = { $value } không phải là số hợp lệ. +cli.validation.jobs.out_of_range = Số lượng tác vụ phải nằm trong khoảng từ { $min } đến { $max }. +cli.validation.scheme.empty = Lược đồ không được để trống. +cli.validation.scheme.invalid_start = Lược đồ “{ $scheme }” phải bắt đầu bằng một chữ cái ASCII. +cli.validation.scheme.invalid = Lược đồ không hợp lệ: “{ $scheme }”. +cli.validation.locale.empty = Thẻ ngôn ngữ không được để trống. +cli.validation.locale.invalid = Thẻ ngôn ngữ không hợp lệ: “{ $locale }”. +cli.validation.color.invalid = Chính sách màu không hợp lệ: “{ $value }”. Lựa chọn hợp lệ: auto, always, never. +cli.validation.emoji.invalid = Chính sách biểu tượng cảm xúc không hợp lệ: “{ $value }”. Lựa chọn hợp lệ: auto, always, never. +cli.validation.progress.invalid = Chính sách tiến trình không hợp lệ: “{ $value }”. Lựa chọn hợp lệ: auto, always, never. +cli.validation.accessibility.invalid = Chính sách trợ năng không hợp lệ: “{ $value }”. Lựa chọn hợp lệ: auto, on, off. +cli.validation.config.expected_object = Các giá trị dòng lệnh lẽ ra phải được tuần tự hoá thành đối tượng, nhưng nhận được { $value }. + +# Thông báo lỗi của Clap. +clap-error-missing-argument = Thiếu đối số bắt buộc: { $argument } +clap-error-missing-subcommand = Thiếu lệnh con. Các lựa chọn sẵn có: { $valid_subcommands } +clap-error-unknown-argument = Đối số không xác định: { $argument } +clap-error-invalid-value = Giá trị không hợp lệ cho { $argument }: { $value } +clap-error-invalid-subcommand = Lệnh con không xác định: { $subcommand } +# Lưu ý: value-validation được diễn đạt khác invalid-value để phân biệt lỗi của +# bộ kiểm tra riêng (ErrorKind::ValueValidation) với lỗi sai kiểu +# (ErrorKind::InvalidValue). +clap-error-value-validation = Kiểm tra thất bại cho { $argument }: { $value } + +# Lỗi và ngữ cảnh khi chạy. +runner.manifest.not_found = Không tìm thấy tệp kê khai “{ $manifest_name }” trong { $directory }. +runner.manifest.not_found.help = Hãy chắc chắn tệp kê khai tồn tại, hoặc truyền `--file` với đường dẫn đúng. +runner.manifest.path_missing_name = Đường dẫn tệp kê khai “{ $path }” không có tên tệp. +runner.manifest.path_utf8 = Đường dẫn tệp kê khai “{ $path }” không phải UTF-8 hợp lệ. +runner.manifest.directory_utf8 = Đường dẫn thư mục tệp kê khai “{ $path }” không phải UTF-8 hợp lệ. +runner.manifest.directory_label = thư mục `{ $directory }` +runner.manifest.current_directory_label = thư mục hiện tại +runner.context.network_policy = Không dựng được chính sách mạng. +runner.context.load_manifest = Không nạp được tệp kê khai tại { $path }. +runner.context.serialise_manifest = Không tuần tự hoá được tệp kê khai. +runner.context.build_graph = Không dựng được đồ thị từ tệp kê khai. +runner.context.generate_ninja = Không tạo được tệp kê khai Ninja. +runner.context.render_graph = Không kết xuất được sản phẩm đồ thị. + +runner.io.create_temp_file = Không tạo được tệp Ninja tạm. +runner.io.write_temp_ninja = Không ghi được tệp Ninja tạm. +runner.io.flush_temp_ninja = Không xả được bộ đệm của tệp Ninja tạm. +runner.io.sync_temp_ninja = Không đồng bộ được tệp Ninja tạm. +runner.io.create_parent_dir = Không tạo được thư mục cha { $path }. +runner.io.create_ninja_file = Không tạo được tệp Ninja tại { $path }. +runner.io.write_ninja_file = Không ghi được tệp Ninja tại { $path }. +runner.io.flush_ninja_file = Không xả được bộ đệm của tệp Ninja tại { $path }. +runner.io.sync_ninja_file = Không đồng bộ được tệp Ninja tại { $path }. +runner.io.open_ambient_dir = Không mở được thư mục xung quanh. +runner.io.no_existing_ancestor = Không có thư mục cha nào tồn tại cho { $path }. +runner.io.derive_relative_path = Không suy ra được đường dẫn Ninja tương đối. +runner.io.non_utf8_path = Không hỗ trợ đường dẫn không phải UTF-8 (đường dẫn: { $path }). +runner.io.write_stdout = Không ghi được tệp kê khai Ninja ra đầu ra chuẩn. +runner.io.flush_stdout = Không xả được bộ đệm đầu ra chuẩn. + +# Chẩn đoán tệp kê khai. +manifest.parse = Phân tích tệp kê khai thất bại. +manifest.structure_error = Lỗi cấu trúc tệp kê khai tại { $name }: { $details } +manifest.yaml.parse = Lỗi phân tích YAML tại dòng { $line }, cột { $column }: { $details } +manifest.yaml.label = YAML không hợp lệ +manifest.yaml.hint.tabs = YAML không cho phép ký tự tab; hãy dùng dấu cách để thụt lề. +manifest.yaml.hint.list_item = Mục danh sách YAML phải bắt đầu bằng “-” và được thụt lề đúng. +manifest.yaml.hint.expected_colon = Đây có vẻ là một mục ánh xạ; thiếu “:” sau khoá. +manifest.yaml.hint.mapping_values = Ánh xạ YAML cần một giá trị sau “:” (hoặc một khối lồng nhau). +manifest.yaml.hint.invalid_token = Thẻ từ YAML không hợp lệ hoặc bất ngờ. +manifest.yaml.hint.escape = Hãy thoát dấu gạch chéo ngược hoặc bỏ các chuỗi thoát không hợp lệ. +manifest.env.missing = Biến môi trường bắt buộc “{ $name }” chưa được đặt. +manifest.env.invalid_utf8 = Biến môi trường “{ $name }” chứa UTF-8 không hợp lệ. +manifest.vars.not_object = Trường `vars` của tệp kê khai phải là ánh xạ hoặc đối tượng. +manifest.read_failed = Không đọc được tệp kê khai tại { $path }. +manifest.resolve_workspace_root = Không xác định được gốc của không gian làm việc. +manifest.workspace_non_utf8 = Đường dẫn gốc của không gian làm việc “{ $path }” không phải UTF-8 hợp lệ. +manifest.path_non_utf8 = Đường dẫn của tệp kê khai “{ $manifest }” không phải UTF-8 hợp lệ: { $path }. +manifest.path_missing_name = Đường dẫn tệp kê khai “{ $path }” không có tên tệp. +manifest.open_workspace_failed = Không mở được không gian làm việc { $workspace } cho tệp kê khai { $manifest }. +manifest.foreach.not_iterable = Biểu thức `foreach` không duyệt được. +manifest.foreach.serialise_item = Không tuần tự hoá được phần tử của `foreach`. +manifest.when.empty = Biểu thức `when` không được để trống. +manifest.when.eval_error = Không tính được biểu thức `when` “{ $expr }”. +manifest.when.template_error = Không kết xuất được mẫu `when` “{ $expr }”. +manifest.target.vars_not_object = Trường `vars` của đích phải là đối tượng, nhưng nhận được { $value }. +manifest.vars.entry_not_object = Mục `vars` của tệp kê khai phải là đối tượng. +manifest.field_not_string = Trường “{ $field }” phải là chuỗi. +manifest.expression.parse_error = Không phân tích được biểu thức { $name }. +manifest.expression.eval_error = Không tính được biểu thức { $name }. + +# Chẩn đoán macro của tệp kê khai. +manifest.macro.signature_missing_identifier = Chữ ký macro thiếu định danh. +manifest.macro.signature_missing_params = Chữ ký macro thiếu tham số. +manifest.macro.compile_failed = Không biên dịch được macro { $name }. +manifest.macro.sequence_invalid = Macro phải được khai báo dưới dạng ánh xạ từ tên sang mẫu. +manifest.macro.register_failed = Không đăng ký được các macro của tệp kê khai. +manifest.macro.not_initialised = Môi trường macro chưa được khởi tạo. +manifest.macro.caller_invalid = Bên gọi macro phải là chuỗi. +manifest.macro.template_load_failed = Không nạp được mẫu của macro. +manifest.macro.init_failed = Không khởi tạo được môi trường macro. +manifest.macro.missing = Thiếu macro { $name }. + +# Lỗi mẫu glob của tệp kê khai. +manifest.glob.unmatched_brace = Mẫu glob không hợp lệ “{ $pattern }”: “{ $character }” không có ký tự tương ứng tại vị trí { $position }. +manifest.glob.invalid_pattern = Mẫu glob không hợp lệ “{ $pattern }”: { $detail }. +manifest.glob.unknown_pattern_error = lỗi mẫu không xác định. +manifest.glob.io_failed = Glob thất bại với “{ $pattern }”: { $detail }. +manifest.glob.unknown_io_error = lỗi vào/ra không xác định. + +# Lỗi của biểu diễn trung gian. +ir.rule_not_found = Không tìm thấy quy tắc “{ $rule }” mà đích “{ $target }” tham chiếu. +ir.multiple_rules = Đích “{ $target }” phải tham chiếu đúng một quy tắc, nhưng nhận được { $rules }. +ir.empty_rule = Đích “{ $target }” phải tham chiếu một quy tắc. +ir.duplicate_outputs = Phát hiện đầu ra trùng lặp: { $outputs }. +ir.circular_dependency = Phát hiện phụ thuộc vòng: { $cycle }. +ir.action_serialisation = Không tuần tự hoá được hành động: { $details }. +ir.invalid_command = Nội suy không hợp lệ trong lệnh: { $snippet }. + +# Lỗi khi tạo tệp Ninja. +ninja_gen.missing_action = Thiếu hành động “{ $id }” mà một cạnh dựng tham chiếu. +ninja_gen.format = Không định dạng được đầu ra của tệp kê khai Ninja. + +# Kiểm tra mẫu máy chủ. +host_pattern.empty = Mẫu máy chủ không được để trống. +host_pattern.contains_scheme = Mẫu máy chủ “{ $pattern }” không được chứa lược đồ URL. +host_pattern.contains_slash = Mẫu máy chủ “{ $pattern }” không được chứa “/”. +host_pattern.missing_suffix = Mẫu máy chủ “{ $pattern }” phải có hậu tố sau “*.”. +host_pattern.empty_label = Mẫu máy chủ “{ $pattern }” chứa một nhãn rỗng. +host_pattern.invalid_chars = Mẫu máy chủ “{ $pattern }” chứa ký tự không hợp lệ. +host_pattern.invalid_label_edge = Nhãn của mẫu máy chủ “{ $pattern }” không được bắt đầu hoặc kết thúc bằng “-”. +host_pattern.label_too_long = Mẫu máy chủ “{ $pattern }” chứa nhãn dài hơn 63 ký tự. +host_pattern.too_long = Mẫu máy chủ “{ $pattern }” vượt quá giới hạn 255 ký tự. + +# Chính sách mạng. +network_policy.scheme.empty = Lược đồ không được để trống. +network_policy.scheme.invalid = Lược đồ “{ $scheme }” chứa ký tự không hợp lệ. +network_policy.allowlist.empty = Danh sách máy chủ được phép không được để trống. +network_policy.scheme.not_allowed = Lược đồ “{ $scheme }” không được phép. +network_policy.missing_host = URL thiếu máy chủ. +network_policy.host.blocked = Máy chủ “{ $host }” bị chính sách chặn. +network_policy.host.not_allowlisted = Máy chủ “{ $host }” không nằm trong danh sách được phép. + +# Cấu hình thư viện chuẩn. +stdlib.config.default_fetch_cache_invalid = Đường dẫn bộ nhớ đệm fetch mặc định phải là tương đối. +stdlib.config.default_which_cache_invalid = Dung lượng bộ nhớ đệm which mặc định phải là số dương. +stdlib.config.workspace_root_absolute = Đường dẫn gốc của không gian làm việc phải là tuyệt đối. +stdlib.config.fetch_response_limit_positive = Giới hạn phản hồi của fetch phải là số dương. +stdlib.config.command_output_limit_positive = Giới hạn thu nhận đầu ra lệnh phải là số dương. +stdlib.config.command_stream_limit_positive = Giới hạn luồng lệnh phải là số dương. +stdlib.config.which_cache_capacity_positive = Dung lượng bộ nhớ đệm which phải là số dương. +stdlib.config.skip_dir_empty = Mục thư mục bị bỏ qua không được để trống. +stdlib.config.skip_dir_navigation = Mục thư mục bị bỏ qua không được chứa “..”. +stdlib.config.skip_dir_separator = Mục thư mục bị bỏ qua không được chứa dấu phân tách đường dẫn. +stdlib.config.fetch_cache_empty = Đường dẫn bộ nhớ đệm fetch không được để trống. +stdlib.config.fetch_cache_not_relative = Đường dẫn bộ nhớ đệm fetch phải là tương đối, nhưng nhận được { $path }. +stdlib.config.fetch_cache_escapes = Đường dẫn bộ nhớ đệm fetch không được ra ngoài không gian làm việc: { $path }. +stdlib.config.open_workspace_root = Không mở được thư mục hiện tại làm gốc không gian làm việc của stdlib. +stdlib.config.resolve_cwd = Không xác định được thư mục hiện tại làm gốc không gian làm việc của stdlib. +stdlib.config.cwd_non_utf8 = Thư mục hiện tại chứa phần không phải UTF-8: { $path }. + +# Chẩn đoán của hàm trợ giúp fetch. +stdlib.fetch.url_invalid = URL không hợp lệ “{ $url }”: { $details }. +stdlib.fetch.disallowed = URL “{ $url }” không được phép: { $details }. +stdlib.fetch.failed = Không tải được “{ $url }”: { $details }. +stdlib.fetch.cache_read_failed = Không đọc được mục bộ nhớ đệm “{ $name }”: { $details }. +stdlib.fetch.cache_open_failed = Không mở được mục bộ nhớ đệm “{ $name }”: { $details }. +stdlib.fetch.response_read_failed = Không đọc được phản hồi từ “{ $url }”: { $details }. +stdlib.fetch.response_buffer_overflow = Tràn bộ đệm khi đọc “{ $url }”. +stdlib.fetch.cache_write_failed = Không ghi được bộ nhớ đệm cho “{ $url }”: { $details }. +stdlib.fetch.response_limit_exceeded = Phản hồi từ “{ $url }” vượt quá giới hạn { $limit } byte. +stdlib.fetch.cache_limit_exceeded = Phản hồi đã lưu đệm “{ $name }” vượt quá giới hạn { $limit } byte. +stdlib.fetch.io_failed = Hành động “{ $action }” thất bại với { $path }: { $details }. +stdlib.fetch.action.sync_cache = đồng bộ bộ nhớ đệm fetch +stdlib.fetch.action.create_cache_dir = tạo thư mục bộ nhớ đệm fetch +stdlib.fetch.action.open_cache_dir = mở thư mục bộ nhớ đệm fetch +stdlib.fetch.action.stat_cache = đọc thông tin mục bộ nhớ đệm fetch +stdlib.fetch.action.open_cache_entry = mở mục bộ nhớ đệm fetch + +# Chẩn đoán của hàm trợ giúp lệnh. +stdlib.command.location = lệnh “{ $command }” trong mẫu “{ $template }” +stdlib.command.spawn_failed = Không khởi chạy được { $location }: { $details }. +stdlib.command.io_failed = { $location } thất bại: { $details }. +stdlib.command.closed_input_early = Đầu vào đã đóng trước khi hoàn tất việc ghi sang lệnh. +stdlib.command.broken_pipe = Đứt ống dẫn khi chạy { $location }: { $details }. +stdlib.command.terminated_by_signal = { $location } bị tín hiệu chấm dứt. +stdlib.command.exited_with_status = { $location } kết thúc với trạng thái { $status }. +stdlib.command.output_limit_exceeded = { $location } vượt quá giới hạn { $mode } là { $limit } byte cho { $stream }. +stdlib.command.timeout = { $location } vượt quá thời hạn { $seconds } giây. +stdlib.command.exit_status_suffix = (trạng thái thoát { $status }) +stdlib.command.signal_suffix = (bị tín hiệu chấm dứt) +stdlib.command.shell.empty = Lệnh shell không được để trống. +stdlib.command.grep.empty_pattern = Mẫu grep không được để trống. +stdlib.command.grep.flags_not_string = Cờ của grep phải là chuỗi. +stdlib.command.quote.invalid = Không đặt được { $arg } trong dấu nháy: { $details }. +stdlib.command.quote.line_break = Đối số chứa ký tự về đầu dòng hoặc xuống dòng không thể đặt trong dấu nháy một cách an toàn. +stdlib.command.input_undefined = Giá trị đầu vào chưa được xác định. +stdlib.command.tempfile.root_required = Cần gốc của không gian làm việc để tạo tệp lệnh tạm. +stdlib.command.tempfile.create_failed = Không tạo được tệp lệnh tạm: { $details }. +stdlib.command.options.invalid_utf8 = Khoá tuỳ chọn của lệnh phải là UTF-8 hợp lệ. +stdlib.command.option.mode_not_string = Chế độ đầu ra phải là chuỗi. +stdlib.command.options.invalid_type = Các tuỳ chọn của lệnh phải là một đối tượng. +stdlib.command.output.mode_unsupported = Chế độ đầu ra không được hỗ trợ: “{ $mode }”. +stdlib.command.output.mode.capture = thu nhận +stdlib.command.output.mode.streaming = truyền luồng +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# Chẩn đoán của hàm trợ giúp đường dẫn. +stdlib.path.io.failed = Hành động “{ $action }” thất bại với { $path } ({ $label }). +stdlib.path.io.failed_with_detail = Hành động “{ $action }” thất bại với { $path }: { $detail }. +stdlib.path.io.failed_with_label_and_detail = Hành động “{ $action }” thất bại với { $path } ({ $label }): { $detail }. +stdlib.path.io.not_found = không tìm thấy +stdlib.path.io.permission_denied = bị từ chối quyền truy cập +stdlib.path.io.already_exists = đã tồn tại +stdlib.path.io.invalid_input = đầu vào không hợp lệ +stdlib.path.io.invalid_data = dữ liệu không hợp lệ +stdlib.path.io.timed_out = hết thời gian chờ +stdlib.path.io.interrupted = bị ngắt +stdlib.path.io.would_block = sẽ gây chặn +stdlib.path.io.write_zero = ghi được không byte +stdlib.path.io.unexpected_eof = kết thúc tệp ngoài dự kiến +stdlib.path.io.broken_pipe = đứt ống dẫn +stdlib.path.io.connection_refused = kết nối bị từ chối +stdlib.path.io.connection_reset = kết nối bị đặt lại +stdlib.path.io.connection_aborted = kết nối bị huỷ +stdlib.path.io.not_connected = chưa kết nối +stdlib.path.io.addr_in_use = địa chỉ đang được dùng +stdlib.path.io.addr_not_available = địa chỉ không khả dụng +stdlib.path.io.out_of_memory = hết bộ nhớ +stdlib.path.io.unsupported = không được hỗ trợ +stdlib.path.io.file_too_large = tệp quá lớn +stdlib.path.io.resource_busy = tài nguyên đang bận +stdlib.path.io.executable_busy = tệp thực thi đang bận +stdlib.path.io.deadlock = bế tắc +stdlib.path.io.crosses_devices = vượt qua ranh giới thiết bị +stdlib.path.io.too_many_links = quá nhiều liên kết +stdlib.path.io.invalid_filename = tên tệp không hợp lệ +stdlib.path.io.arg_list_too_long = danh sách đối số quá dài +stdlib.path.io.stale_handle = handle tệp mạng đã cũ +stdlib.path.io.storage_full = bộ lưu trữ đã đầy +stdlib.path.io.not_seekable = không định vị được +stdlib.path.io.network_down = mạng không hoạt động +stdlib.path.io.network_unreachable = không tới được mạng +stdlib.path.io.host_unreachable = không tới được máy chủ +stdlib.path.io.other = lỗi vào/ra +stdlib.path.action.canonicalize = chuẩn hoá đường dẫn +stdlib.path.action.open_directory = mở thư mục +stdlib.path.action.stat = đọc thông tin +stdlib.path.action.read = đọc +stdlib.path.action.open_file = mở tệp +stdlib.path.with_suffix.empty_separator = with_suffix cần một dấu phân tách không rỗng. +stdlib.path.relative_to.mismatch = { $path } không tương đối so với { $root }. +stdlib.path.expanduser.unsupported = Không hỗ trợ mở rộng ~ cho một người dùng cụ thể. +stdlib.path.expanduser.no_home = Không mở rộng được ~: chưa đặt biến môi trường nào cho thư mục cá nhân. +stdlib.path.contents.unsupported_encoding = Bảng mã không được hỗ trợ: “{ $encoding }”. +stdlib.path.hash.unsupported_algorithm = Thuật toán băm không được hỗ trợ: “{ $algorithm }”. +stdlib.path.hash.unsupported_algorithm_legacy = Thuật toán băm không được hỗ trợ: “{ $algorithm }” (hãy bật tính năng “{ $feature }”). + +# Chẩn đoán của các hàm trợ giúp tập hợp. +stdlib.collections.flatten.expected_sequence = flatten mong đợi các phần tử của một dãy nhưng lại gặp { $kind }. +stdlib.collections.group_by.empty_attribute = group_by cần một thuộc tính không rỗng. +stdlib.collections.group_by.unresolved = group_by không tìm được “{ $attr }” trên phần tử kiểu { $kind }. + +# Chẩn đoán của các hàm trợ giúp thời gian. +stdlib.time.offset.invalid = Độ lệch now “{ $offset }” không hợp lệ: cần “+HH:MM[:SS]” hoặc “Z”. +stdlib.time.timedelta.overflow = Tràn số trong timedelta khi cộng thêm { $component }. +stdlib.time.label.weeks = tuần +stdlib.time.label.days = ngày +stdlib.time.label.hours = giờ +stdlib.time.label.minutes = phút +stdlib.time.label.seconds = giây +stdlib.time.label.milliseconds = mili giây +stdlib.time.label.microseconds = micro giây +stdlib.time.label.nanoseconds = nano giây + +# Chẩn đoán của hàm trợ giúp which. +stdlib.which.not_found = [netsuke::jinja::which::not_found] không tìm thấy lệnh “{ $command }” sau khi kiểm tra { $count } mục PATH. Xem trước: { $preview } +stdlib.which.not_found.hint.cwd_auto = Các đoạn rỗng trong PATH bị bỏ qua; dùng cwd_mode="auto" để tính cả thư mục làm việc. +stdlib.which.not_found.hint.cwd_always = Đặt cwd_mode="always" để tính cả thư mục hiện tại. +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] lệnh “{ $command }” tại “{ $path }” không tồn tại hoặc không thực thi được. +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = +stdlib.which.path_entry.non_utf8 = Mục PATH số { $index } chứa ký tự không phải UTF-8; Netsuke yêu cầu đường dẫn UTF-8. +stdlib.which.command.empty = which cần một chuỗi không rỗng. +stdlib.which.cwd_mode.invalid = cwd_mode phải là “auto”, “always” hoặc “never”, nhưng nhận được “{ $mode }”. +stdlib.which.cwd.resolve_failed = Không xác định được thư mục hiện tại: { $details }. +stdlib.which.cwd.non_utf8 = Thư mục hiện tại chứa phần không phải UTF-8. +stdlib.which.canonicalize_failed = Không chuẩn hoá được “{ $path }”: { $details }. +stdlib.which.is_executable = Không xác định được “{ $path }” có thực thi được hay không: { $details }. +stdlib.which.canonicalize_non_utf8 = Đường dẫn chuẩn tắc chứa phần không phải UTF-8. +stdlib.which.workspace_non_utf8 = Đường dẫn không gian làm việc chứa phần không phải UTF-8 khi phân giải lệnh “{ $command }”: { $path }. +stdlib.which.walkdir_error = Lỗi khi duyệt không gian làm việc trong lúc phân giải lệnh: { $details }. + +# Đăng ký thư viện chuẩn. +stdlib.register.open_dir = Không mở được thư mục hiện tại để đăng ký stdlib. +stdlib.register.resolve_dir = Không xác định được thư mục hiện tại để đăng ký stdlib. +stdlib.register.dir_non_utf8 = Thư mục hiện tại chứa phần không phải UTF-8: { $path }. + +# Báo cáo trạng thái cho chế độ đầu ra dễ tiếp cận. +status.state.pending = đang chờ +status.state.running = đang chạy +status.state.done = xong +status.state.failed = thất bại +status.stage.label = Giai đoạn { $current }/{ $total }: { $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label } ({ $task_progress }) +status.task.progress_label = Tác vụ { $current }/{ $total } +status.task.progress_update = { $task }: { $description } +status.stage.manifest_ingestion = Đang đọc tệp kê khai +status.stage.initial_yaml_parsing = Đang phân tích tài liệu YAML +status.stage.template_expansion = Đang mở rộng các chỉ thị mẫu +status.stage.final_rendering = Đang giải tuần tự và kết xuất giá trị của tệp kê khai +status.stage.ir_generation_validation = Đang dựng và kiểm tra đồ thị phụ thuộc +status.stage.ninja_synthesis = Đang tổng hợp kế hoạch dựng Ninja +status.stage.ninja_synthesis_execute = Đang tổng hợp kế hoạch Ninja và chạy { $tool } +status.stage.graph_rendering = Đang kết xuất sản phẩm đồ thị +status.stage.graph_rendering_with_tool = Đang kết xuất { $tool } +status.complete = { $tool } đã hoàn tất. +status.timing.summary_header = Tóm tắt thời gian theo giai đoạn: +status.timing.stage_line = - { $label }: { $duration } +status.timing.total_line = Tổng thời gian của dây chuyền: { $duration } +status.tool.build = Dựng +status.tool.clean = Dọn dẹp +status.tool.graph = Đồ thị +status.tool.graph_html = Đồ thị (HTML) +status.tool.generate = Tạo + +# Chuỗi của bộ kết xuất đồ thị sang HTML. +graph.html.title = Đồ thị dựng của Netsuke +graph.html.heading = Đồ thị dựng của Netsuke +graph.html.description = Đồ thị dựng do Netsuke kết xuất +graph.html.outline.summary = Đích và phụ thuộc (dàn ý văn bản) +graph.html.outline.no_inputs = Không có đầu vào +graph.html.noscript.notice = JavaScript đang tắt. Dàn ý văn bản ở trên chứa toàn bộ đồ thị; mã nguồn DOT nằm bên dưới. + +# Tiền tố ngữ nghĩa cho đầu ra dễ tiếp cận. +semantic.prefix.error = Lỗi: +semantic.prefix.warning = Cảnh báo: +semantic.prefix.success = Thành công: +semantic.prefix.info = Thông tin: +semantic.prefix.timing = Thời gian: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# Ví dụ về dạng số nhiều cho người dịch. +# Tiếng Việt chỉ dùng một hạng CLDR (`other`), vì danh từ không đổi theo số. +example.files_processed = { $count -> + *[other] Đã xử lý { $count } tệp. +} + +example.errors_found = { $count -> + [0] Không tìm thấy lỗi nào. + *[other] Tìm thấy { $count } lỗi. +} diff --git a/locales/zh-Hans/messages.ftl b/locales/zh-Hans/messages.ftl new file mode 100644 index 000000000..533efc617 --- /dev/null +++ b/locales/zh-Hans/messages.ftl @@ -0,0 +1,394 @@ +# Netsuke 命令行的本地化资源(简体中文)。 + +cli.about = Netsuke 将 YAML + Jinja 清单编译为 Ninja 构建计划。 +cli.long_about = Netsuke 把 YAML + Jinja 清单转换为可复现的 Ninja 图,并以安全的默认设置运行 Ninja。 +cli.usage = { $usage } + +# 全局选项的帮助文本。 +cli.flag.file.help = 要使用的 Netsuke 清单文件路径。 +cli.flag.directory.help = 按照在此目录中启动的方式运行。 +cli.flag.config.help = 配置文件路径,跳过自动查找。 +cli.flag.jobs.help = 设置并行构建任务的数量。 +cli.flag.verbose.help = 启用详细的诊断日志和完成时的耗时摘要。 +cli.flag.locale.help = 命令行文案的区域标记(例如:en-US、zh-Hans)。 +cli.flag.fetch_allow_scheme.help = fetch 辅助函数额外允许的 URL 方案。 +cli.flag.fetch_allow_host.help = 启用默认拒绝时仍然允许的主机名。 +cli.flag.fetch_block_host.help = 始终阻止的主机名,即使在别处被允许。 +cli.flag.fetch_default_deny.help = 默认拒绝所有主机;只放行声明的允许列表。 +cli.flag.json.help = 输出机器可读的 JSON。 +cli.flag.no_input.help = 绝不读取交互式输入。 +cli.flag.color.help = 彩色输出策略(auto、always、never)。 +cli.flag.emoji.help = 表情符号策略(auto、always、never)。 +cli.flag.progress.help = 进度显示策略(auto、always、never)。 +cli.flag.accessibility.help = 无障碍输出策略(auto、on、off)。 +cli.flag.default_targets.help = 未指定目标时使用的默认构建目标。 + +# 子命令说明。 +cli.subcommand.build.about = 构建清单中定义的目标(默认)。 +cli.subcommand.build.long_about = 构建所请求的目标;若未指定,则使用清单中的默认目标。 +cli.subcommand.clean.about = 通过 Ninja 删除构建产物。 +cli.subcommand.clean.long_about = 生成临时 Ninja 文件,然后运行 `ninja -t clean`。 +cli.subcommand.graph.about = 输出构建依赖图。默认格式为 DOT。 +cli.subcommand.graph.long_about = 将解析后的 Netsuke 清单投影为规范的构建图,并写为 Graphviz DOT;使用 `--html` 时写为独立的 HTML 页面。使用 `--output <文件>` 写入文件;`-` 写入标准输出。 +cli.subcommand.generate.about = 生成 Ninja 清单但不运行 Ninja。 +cli.subcommand.generate.long_about = 将生成的 Ninja 清单写入标准输出,或写入用 `--output` 选定的文件。 + +# build 子命令选项的帮助文本。 +cli.subcommand.build.flag.targets.help = 要构建的目标(省略时使用清单中的默认目标)。 + +# graph 子命令选项的帮助文本。 +cli.subcommand.graph.flag.html.help = 将图渲染为独立的 HTML 页面,而不是 DOT。 +cli.subcommand.graph.flag.output.help = 将图产物写入文件;标准输出请使用 `-`。 + +# generate 子命令选项的帮助文本。 +cli.subcommand.generate.flag.output.help = 将生成的 Ninja 清单写入文件,而不是标准输出。 + +# 命令行校验错误。 +cli.validation.jobs.invalid_number = { $value } 不是有效的数字。 +cli.validation.jobs.out_of_range = 任务数必须介于 { $min } 与 { $max } 之间。 +cli.validation.scheme.empty = 方案不能为空。 +cli.validation.scheme.invalid_start = 方案“{ $scheme }”必须以 ASCII 字母开头。 +cli.validation.scheme.invalid = 无效的方案“{ $scheme }”。 +cli.validation.locale.empty = 区域标记不能为空。 +cli.validation.locale.invalid = 无效的区域标记“{ $locale }”。 +cli.validation.color.invalid = 无效的颜色策略“{ $value }”。有效取值:auto、always、never。 +cli.validation.emoji.invalid = 无效的表情符号策略“{ $value }”。有效取值:auto、always、never。 +cli.validation.progress.invalid = 无效的进度策略“{ $value }”。有效取值:auto、always、never。 +cli.validation.accessibility.invalid = 无效的无障碍策略“{ $value }”。有效取值:auto、on、off。 +cli.validation.config.expected_object = 命令行的值本应序列化为对象,却得到 { $value }。 + +# Clap 的错误消息。 +clap-error-missing-argument = 缺少必需的参数:{ $argument } +clap-error-missing-subcommand = 缺少子命令。可用选项:{ $valid_subcommands } +clap-error-unknown-argument = 未知参数:{ $argument } +clap-error-invalid-value = { $argument } 的取值无效:{ $value } +clap-error-invalid-subcommand = 未知子命令:{ $subcommand } +# 注意:value-validation 的措辞与 invalid-value 不同,以便区分自定义校验器的 +# 失败(ErrorKind::ValueValidation)与类型不匹配(ErrorKind::InvalidValue)。 +clap-error-value-validation = { $argument } 校验失败:{ $value } + +# 运行时的错误与上下文。 +runner.manifest.not_found = 在 { $directory } 中找不到清单“{ $manifest_name }”。 +runner.manifest.not_found.help = 请确认清单存在,或用正确的路径指定 `--file`。 +runner.manifest.path_missing_name = 清单路径“{ $path }”没有文件名。 +runner.manifest.path_utf8 = 清单路径“{ $path }”不是有效的 UTF-8。 +runner.manifest.directory_utf8 = 清单目录路径“{ $path }”不是有效的 UTF-8。 +runner.manifest.directory_label = 目录 `{ $directory }` +runner.manifest.current_directory_label = 当前目录 +runner.context.network_policy = 无法构建网络策略。 +runner.context.load_manifest = 无法加载 { $path } 处的清单。 +runner.context.serialise_manifest = 无法序列化清单。 +runner.context.build_graph = 无法根据清单构建图。 +runner.context.generate_ninja = 无法生成 Ninja 清单。 +runner.context.render_graph = 无法渲染图产物。 + +runner.io.create_temp_file = 无法创建临时 Ninja 文件。 +runner.io.write_temp_ninja = 无法写入临时 Ninja 文件。 +runner.io.flush_temp_ninja = 无法刷新临时 Ninja 文件的缓冲区。 +runner.io.sync_temp_ninja = 无法同步临时 Ninja 文件。 +runner.io.create_parent_dir = 无法创建父目录 { $path }。 +runner.io.create_ninja_file = 无法在 { $path } 创建 Ninja 文件。 +runner.io.write_ninja_file = 无法写入 { $path } 处的 Ninja 文件。 +runner.io.flush_ninja_file = 无法刷新 { $path } 处 Ninja 文件的缓冲区。 +runner.io.sync_ninja_file = 无法同步 { $path } 处的 Ninja 文件。 +runner.io.open_ambient_dir = 无法打开周围目录。 +runner.io.no_existing_ancestor = { $path } 没有已存在的上级目录。 +runner.io.derive_relative_path = 无法推导 Ninja 的相对路径。 +runner.io.non_utf8_path = 不支持非 UTF-8 路径(路径:{ $path })。 +runner.io.write_stdout = 无法将 Ninja 清单写入标准输出。 +runner.io.flush_stdout = 无法刷新标准输出的缓冲区。 + +# 清单诊断。 +manifest.parse = 清单解析失败。 +manifest.structure_error = 清单在 { $name } 处存在结构错误:{ $details } +manifest.yaml.parse = 第 { $line } 行第 { $column } 列出现 YAML 解析错误:{ $details } +manifest.yaml.label = 无效的 YAML +manifest.yaml.hint.tabs = YAML 不允许制表符;缩进请使用空格。 +manifest.yaml.hint.list_item = YAML 列表项必须以“-”开头并正确缩进。 +manifest.yaml.hint.expected_colon = 这看起来是映射条目;键后缺少“:”。 +manifest.yaml.hint.mapping_values = YAML 映射在“:”之后需要一个值(或嵌套块)。 +manifest.yaml.hint.invalid_token = YAML 记号无效或出乎意料。 +manifest.yaml.hint.escape = 请转义反斜杠,或删除无效的转义序列。 +manifest.env.missing = 未设置必需的环境变量“{ $name }”。 +manifest.env.invalid_utf8 = 环境变量“{ $name }”包含无效的 UTF-8。 +manifest.vars.not_object = 清单的 `vars` 必须是映射或对象。 +manifest.read_failed = 无法读取 { $path } 处的清单。 +manifest.resolve_workspace_root = 无法确定工作区根目录。 +manifest.workspace_non_utf8 = 工作区根路径“{ $path }”不是有效的 UTF-8。 +manifest.path_non_utf8 = 清单“{ $manifest }”的路径不是有效的 UTF-8:{ $path }。 +manifest.path_missing_name = 清单路径“{ $path }”没有文件名。 +manifest.open_workspace_failed = 无法为清单 { $manifest } 打开工作区 { $workspace }。 +manifest.foreach.not_iterable = `foreach` 表达式不可迭代。 +manifest.foreach.serialise_item = 无法序列化 `foreach` 的元素。 +manifest.when.empty = `when` 表达式不能为空。 +manifest.when.eval_error = 无法求值 `when` 表达式“{ $expr }”。 +manifest.when.template_error = 无法渲染 `when` 模板“{ $expr }”。 +manifest.target.vars_not_object = 目标的 `vars` 必须是对象,却得到 { $value }。 +manifest.vars.entry_not_object = 清单的 `vars` 条目必须是对象。 +manifest.field_not_string = 字段“{ $field }”必须是字符串。 +manifest.expression.parse_error = 无法解析 { $name } 表达式。 +manifest.expression.eval_error = 无法求值 { $name } 表达式。 + +# 清单宏的诊断。 +manifest.macro.signature_missing_identifier = 宏签名缺少标识符。 +manifest.macro.signature_missing_params = 宏签名缺少参数。 +manifest.macro.compile_failed = 无法编译宏 { $name }。 +manifest.macro.sequence_invalid = 宏必须定义为从名称到模板的映射。 +manifest.macro.register_failed = 无法注册清单中的宏。 +manifest.macro.not_initialised = 宏环境尚未初始化。 +manifest.macro.caller_invalid = 宏的调用方必须是字符串。 +manifest.macro.template_load_failed = 无法加载宏模板。 +manifest.macro.init_failed = 无法初始化宏环境。 +manifest.macro.missing = 缺少宏 { $name }。 + +# 清单的 glob 错误。 +manifest.glob.unmatched_brace = 无效的 glob 模式“{ $pattern }”:位置 { $position } 处的“{ $character }”没有配对。 +manifest.glob.invalid_pattern = 无效的 glob 模式“{ $pattern }”:{ $detail }。 +manifest.glob.unknown_pattern_error = 未知的模式错误。 +manifest.glob.io_failed = 对“{ $pattern }”执行 glob 失败:{ $detail }。 +manifest.glob.unknown_io_error = 未知的输入输出错误。 + +# 中间表示的错误。 +ir.rule_not_found = 找不到目标“{ $target }”引用的规则“{ $rule }”。 +ir.multiple_rules = 目标“{ $target }”必须只引用一条规则,却得到 { $rules }。 +ir.empty_rule = 目标“{ $target }”必须引用一条规则。 +ir.duplicate_outputs = 检测到重复输出:{ $outputs }。 +ir.circular_dependency = 检测到循环依赖:{ $cycle }。 +ir.action_serialisation = 无法序列化动作:{ $details }。 +ir.invalid_command = 命令中的插值无效:{ $snippet }。 + +# Ninja 生成错误。 +ninja_gen.missing_action = 缺少构建边引用的动作“{ $id }”。 +ninja_gen.format = 无法格式化 Ninja 清单的输出。 + +# 主机模式校验。 +host_pattern.empty = 主机模式不能为空。 +host_pattern.contains_scheme = 主机模式“{ $pattern }”不能包含 URL 方案。 +host_pattern.contains_slash = 主机模式“{ $pattern }”不能包含“/”。 +host_pattern.missing_suffix = 主机模式“{ $pattern }”必须在“*.”之后带有后缀。 +host_pattern.empty_label = 主机模式“{ $pattern }”包含空标签。 +host_pattern.invalid_chars = 主机模式“{ $pattern }”包含无效字符。 +host_pattern.invalid_label_edge = 主机模式“{ $pattern }”的标签不能以“-”开头或结尾。 +host_pattern.label_too_long = 主机模式“{ $pattern }”包含超过 63 个字符的标签。 +host_pattern.too_long = 主机模式“{ $pattern }”超出 255 个字符的上限。 + +# 网络策略。 +network_policy.scheme.empty = 方案不能为空。 +network_policy.scheme.invalid = 方案“{ $scheme }”包含无效字符。 +network_policy.allowlist.empty = 主机允许列表不能为空。 +network_policy.scheme.not_allowed = 不允许使用方案“{ $scheme }”。 +network_policy.missing_host = URL 缺少主机。 +network_policy.host.blocked = 主机“{ $host }”已被策略阻止。 +network_policy.host.not_allowlisted = 主机“{ $host }”不在允许列表中。 + +# 标准库配置。 +stdlib.config.default_fetch_cache_invalid = fetch 缓存的默认路径必须是相对路径。 +stdlib.config.default_which_cache_invalid = which 缓存的默认容量必须为正数。 +stdlib.config.workspace_root_absolute = 工作区根路径必须是绝对路径。 +stdlib.config.fetch_response_limit_positive = fetch 的响应上限必须为正数。 +stdlib.config.command_output_limit_positive = 命令输出的捕获上限必须为正数。 +stdlib.config.command_stream_limit_positive = 命令的流式上限必须为正数。 +stdlib.config.which_cache_capacity_positive = which 缓存的容量必须为正数。 +stdlib.config.skip_dir_empty = 跳过目录的条目不能为空。 +stdlib.config.skip_dir_navigation = 跳过目录的条目不能包含“..”。 +stdlib.config.skip_dir_separator = 跳过目录的条目不能包含路径分隔符。 +stdlib.config.fetch_cache_empty = fetch 缓存的路径不能为空。 +stdlib.config.fetch_cache_not_relative = fetch 缓存的路径必须是相对路径,却得到 { $path }。 +stdlib.config.fetch_cache_escapes = fetch 缓存的路径不能越出工作区:{ $path }。 +stdlib.config.open_workspace_root = 无法将当前目录作为 stdlib 工作区根目录打开。 +stdlib.config.resolve_cwd = 无法将当前目录确定为 stdlib 工作区根目录。 +stdlib.config.cwd_non_utf8 = 当前目录包含非 UTF-8 的部分:{ $path }。 + +# fetch 辅助函数的诊断。 +stdlib.fetch.url_invalid = 无效的 URL“{ $url }”:{ $details }。 +stdlib.fetch.disallowed = 不允许使用 URL“{ $url }”:{ $details }。 +stdlib.fetch.failed = 无法获取“{ $url }”:{ $details }。 +stdlib.fetch.cache_read_failed = 无法读取缓存条目“{ $name }”:{ $details }。 +stdlib.fetch.cache_open_failed = 无法打开缓存条目“{ $name }”:{ $details }。 +stdlib.fetch.response_read_failed = 无法读取来自“{ $url }”的响应:{ $details }。 +stdlib.fetch.response_buffer_overflow = 读取“{ $url }”时缓冲区溢出。 +stdlib.fetch.cache_write_failed = 无法写入“{ $url }”的缓存:{ $details }。 +stdlib.fetch.response_limit_exceeded = 来自“{ $url }”的响应超过 { $limit } 字节的上限。 +stdlib.fetch.cache_limit_exceeded = 缓存的响应“{ $name }”超过 { $limit } 字节的上限。 +stdlib.fetch.io_failed = 对 { $path } 执行“{ $action }”失败:{ $details }。 +stdlib.fetch.action.sync_cache = 同步 fetch 缓存 +stdlib.fetch.action.create_cache_dir = 创建 fetch 缓存目录 +stdlib.fetch.action.open_cache_dir = 打开 fetch 缓存目录 +stdlib.fetch.action.stat_cache = 查询 fetch 缓存条目信息 +stdlib.fetch.action.open_cache_entry = 打开 fetch 缓存条目 + +# 命令辅助函数的诊断。 +stdlib.command.location = 模板“{ $template }”中的命令“{ $command }” +stdlib.command.spawn_failed = 无法启动 { $location }:{ $details }。 +stdlib.command.io_failed = { $location } 失败:{ $details }。 +stdlib.command.closed_input_early = 尚未写完命令,输入就已关闭。 +stdlib.command.broken_pipe = 运行 { $location } 时管道中断:{ $details }。 +stdlib.command.terminated_by_signal = { $location } 被信号终止。 +stdlib.command.exited_with_status = { $location } 以状态 { $status } 退出。 +stdlib.command.output_limit_exceeded = { $location } 对 { $stream } 超过了 { $mode } 的 { $limit } 字节上限。 +stdlib.command.timeout = { $location } 超过 { $seconds } 秒的时限。 +stdlib.command.exit_status_suffix = (退出状态 { $status }) +stdlib.command.signal_suffix = (被信号终止) +stdlib.command.shell.empty = shell 命令不能为空。 +stdlib.command.grep.empty_pattern = grep 模式不能为空。 +stdlib.command.grep.flags_not_string = grep 的标志必须是字符串。 +stdlib.command.quote.invalid = 无法为 { $arg } 加引号:{ $details }。 +stdlib.command.quote.line_break = 含有回车或换行的参数无法安全加引号。 +stdlib.command.input_undefined = 输入值未定义。 +stdlib.command.tempfile.root_required = 创建命令临时文件需要工作区根目录。 +stdlib.command.tempfile.create_failed = 无法创建命令临时文件:{ $details }。 +stdlib.command.options.invalid_utf8 = 命令选项的键必须是有效的 UTF-8。 +stdlib.command.option.mode_not_string = 输出模式必须是字符串。 +stdlib.command.options.invalid_type = 命令选项必须是对象。 +stdlib.command.output.mode_unsupported = 不支持的输出模式“{ $mode }”。 +stdlib.command.output.mode.capture = 捕获 +stdlib.command.output.mode.streaming = 流式 +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# 路径辅助函数的诊断。 +stdlib.path.io.failed = 对 { $path } 执行“{ $action }”失败({ $label })。 +stdlib.path.io.failed_with_detail = 对 { $path } 执行“{ $action }”失败:{ $detail }。 +stdlib.path.io.failed_with_label_and_detail = 对 { $path } 执行“{ $action }”失败({ $label }):{ $detail }。 +stdlib.path.io.not_found = 未找到 +stdlib.path.io.permission_denied = 权限被拒绝 +stdlib.path.io.already_exists = 已存在 +stdlib.path.io.invalid_input = 无效输入 +stdlib.path.io.invalid_data = 无效数据 +stdlib.path.io.timed_out = 已超时 +stdlib.path.io.interrupted = 已中断 +stdlib.path.io.would_block = 将会阻塞 +stdlib.path.io.write_zero = 写入零字节 +stdlib.path.io.unexpected_eof = 意外的文件结尾 +stdlib.path.io.broken_pipe = 管道中断 +stdlib.path.io.connection_refused = 连接被拒绝 +stdlib.path.io.connection_reset = 连接被重置 +stdlib.path.io.connection_aborted = 连接被中止 +stdlib.path.io.not_connected = 尚未连接 +stdlib.path.io.addr_in_use = 地址已被占用 +stdlib.path.io.addr_not_available = 地址不可用 +stdlib.path.io.out_of_memory = 内存不足 +stdlib.path.io.unsupported = 不受支持 +stdlib.path.io.file_too_large = 文件过大 +stdlib.path.io.resource_busy = 资源忙 +stdlib.path.io.executable_busy = 可执行文件忙 +stdlib.path.io.deadlock = 死锁 +stdlib.path.io.crosses_devices = 跨越设备 +stdlib.path.io.too_many_links = 链接过多 +stdlib.path.io.invalid_filename = 无效的文件名 +stdlib.path.io.arg_list_too_long = 参数列表过长 +stdlib.path.io.stale_handle = 失效的网络文件句柄 +stdlib.path.io.storage_full = 存储空间已满 +stdlib.path.io.not_seekable = 无法定位 +stdlib.path.io.network_down = 网络已中断 +stdlib.path.io.network_unreachable = 网络不可达 +stdlib.path.io.host_unreachable = 主机不可达 +stdlib.path.io.other = 输入输出错误 +stdlib.path.action.canonicalize = 规范化 +stdlib.path.action.open_directory = 打开目录 +stdlib.path.action.stat = 查询信息 +stdlib.path.action.read = 读取 +stdlib.path.action.open_file = 打开文件 +stdlib.path.with_suffix.empty_separator = with_suffix 需要非空的分隔符。 +stdlib.path.relative_to.mismatch = { $path } 不是相对于 { $root } 的路径。 +stdlib.path.expanduser.unsupported = 不支持针对特定用户展开 ~。 +stdlib.path.expanduser.no_home = 无法展开 ~:未设置任何主目录环境变量。 +stdlib.path.contents.unsupported_encoding = 不支持的编码“{ $encoding }”。 +stdlib.path.hash.unsupported_algorithm = 不支持的散列算法“{ $algorithm }”。 +stdlib.path.hash.unsupported_algorithm_legacy = 不支持的散列算法“{ $algorithm }”(请启用特性“{ $feature }”)。 + +# 集合辅助函数的诊断。 +stdlib.collections.flatten.expected_sequence = flatten 期望序列元素,却发现 { $kind }。 +stdlib.collections.group_by.empty_attribute = group_by 需要非空的属性。 +stdlib.collections.group_by.unresolved = group_by 无法在类型为 { $kind } 的元素上解析“{ $attr }”。 + +# 时间辅助函数的诊断。 +stdlib.time.offset.invalid = now 的偏移“{ $offset }”无效:应为“+HH:MM[:SS]”或“Z”。 +stdlib.time.timedelta.overflow = 累加 { $component } 时 timedelta 溢出。 +stdlib.time.label.weeks = 周 +stdlib.time.label.days = 天 +stdlib.time.label.hours = 小时 +stdlib.time.label.minutes = 分钟 +stdlib.time.label.seconds = 秒 +stdlib.time.label.milliseconds = 毫秒 +stdlib.time.label.microseconds = 微秒 +stdlib.time.label.nanoseconds = 纳秒 + +# which 辅助函数的诊断。 +stdlib.which.not_found = [netsuke::jinja::which::not_found] 检查了 { $count } 个 PATH 条目后仍未找到命令“{ $command }”。预览:{ $preview } +stdlib.which.not_found.hint.cwd_auto = PATH 中的空段会被忽略;如需纳入工作目录,请使用 cwd_mode="auto"。 +stdlib.which.not_found.hint.cwd_always = 如需纳入当前目录,请设置 cwd_mode="always"。 +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] “{ $path }”中的命令“{ $command }”不存在或不可执行。 +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = <空> +stdlib.which.path_entry.non_utf8 = 第 { $index } 个 PATH 条目包含非 UTF-8 字符;Netsuke 需要 UTF-8 路径。 +stdlib.which.command.empty = which 需要非空的字符串。 +stdlib.which.cwd_mode.invalid = cwd_mode 必须是“auto”、“always”或“never”,却得到“{ $mode }”。 +stdlib.which.cwd.resolve_failed = 无法确定当前目录:{ $details }。 +stdlib.which.cwd.non_utf8 = 当前目录包含非 UTF-8 的部分。 +stdlib.which.canonicalize_failed = 无法规范化“{ $path }”:{ $details }。 +stdlib.which.is_executable = 无法判断“{ $path }”是否可执行:{ $details }。 +stdlib.which.canonicalize_non_utf8 = 规范路径包含非 UTF-8 的部分。 +stdlib.which.workspace_non_utf8 = 解析命令“{ $command }”时,工作区路径包含非 UTF-8 的部分:{ $path }。 +stdlib.which.walkdir_error = 解析命令时遍历工作区出错:{ $details }。 + +# 标准库注册。 +stdlib.register.open_dir = 无法为注册 stdlib 打开当前目录。 +stdlib.register.resolve_dir = 无法为注册 stdlib 确定当前目录。 +stdlib.register.dir_non_utf8 = 当前目录包含非 UTF-8 的部分:{ $path }。 + +# 无障碍输出模式的状态报告。 +status.state.pending = 等待中 +status.state.running = 进行中 +status.state.done = 已完成 +status.state.failed = 已失败 +status.stage.label = 阶段 { $current }/{ $total }:{ $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label }({ $task_progress }) +status.task.progress_label = 任务 { $current }/{ $total } +status.task.progress_update = { $task }:{ $description } +status.stage.manifest_ingestion = 正在读取清单文件 +status.stage.initial_yaml_parsing = 正在解析 YAML 文档 +status.stage.template_expansion = 正在展开模板指令 +status.stage.final_rendering = 正在反序列化并渲染清单的取值 +status.stage.ir_generation_validation = 正在构建并校验依赖图 +status.stage.ninja_synthesis = 正在合成 Ninja 构建计划 +status.stage.ninja_synthesis_execute = 正在合成 Ninja 计划并运行 { $tool } +status.stage.graph_rendering = 正在渲染图产物 +status.stage.graph_rendering_with_tool = 正在渲染 { $tool } +status.complete = { $tool } 已完成。 +status.timing.summary_header = 各阶段耗时汇总: +status.timing.stage_line = - { $label }:{ $duration } +status.timing.total_line = 流水线总耗时:{ $duration } +status.tool.build = 构建 +status.tool.clean = 清理 +status.tool.graph = 图 +status.tool.graph_html = 图(HTML) +status.tool.generate = 生成 + +# 图的 HTML 渲染文案。 +graph.html.title = Netsuke 构建图 +graph.html.heading = Netsuke 构建图 +graph.html.description = 由 Netsuke 渲染的构建图 +graph.html.outline.summary = 目标与依赖(文本大纲) +graph.html.outline.no_inputs = 无输入 +graph.html.noscript.notice = JavaScript 已禁用。上面的文本大纲即完整的图;其后是 DOT 源码。 + +# 无障碍输出的语义前缀。 +semantic.prefix.error = 错误: +semantic.prefix.warning = 警告: +semantic.prefix.success = 成功: +semantic.prefix.info = 信息: +semantic.prefix.timing = 耗时: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# 供译者参考的复数形式示例。 +# 中文没有语法上的复数变化,因此 CLDR 只有 `other` 一个类别。 +example.files_processed = { $count -> + *[other] 已处理 { $count } 个文件。 +} + +example.errors_found = { $count -> + [0] 未发现错误。 + *[other] 发现 { $count } 个错误。 +} diff --git a/locales/zh-Hant/messages.ftl b/locales/zh-Hant/messages.ftl new file mode 100644 index 000000000..0a8e81db7 --- /dev/null +++ b/locales/zh-Hant/messages.ftl @@ -0,0 +1,394 @@ +# Netsuke 命令列的在地化資源(繁體中文)。 + +cli.about = Netsuke 會將 YAML + Jinja 資訊清單編譯成 Ninja 建置計畫。 +cli.long_about = Netsuke 把 YAML + Jinja 資訊清單轉換成可重現的 Ninja 圖,並以安全的預設值執行 Ninja。 +cli.usage = { $usage } + +# 全域選項的說明文字。 +cli.flag.file.help = 要使用的 Netsuke 資訊清單檔案路徑。 +cli.flag.directory.help = 以在此目錄中啟動的方式執行。 +cli.flag.config.help = 設定檔的路徑,略過自動搜尋。 +cli.flag.jobs.help = 設定平行建置工作的數量。 +cli.flag.verbose.help = 啟用詳細的診斷記錄與完成時的耗時摘要。 +cli.flag.locale.help = 命令列文字的地區設定標記(例如:en-US、zh-Hant)。 +cli.flag.fetch_allow_scheme.help = fetch 輔助函式額外允許的 URL 通訊協定。 +cli.flag.fetch_allow_host.help = 啟用預設拒絕時仍然允許的主機名稱。 +cli.flag.fetch_block_host.help = 一律封鎖的主機名稱,即使在別處獲得允許。 +cli.flag.fetch_default_deny.help = 預設拒絕所有主機;只放行所宣告的允許清單。 +cli.flag.json.help = 輸出機器可讀的 JSON。 +cli.flag.no_input.help = 絕不讀取互動式輸入。 +cli.flag.color.help = 彩色輸出原則(auto、always、never)。 +cli.flag.emoji.help = 表情符號原則(auto、always、never)。 +cli.flag.progress.help = 進度顯示原則(auto、always、never)。 +cli.flag.accessibility.help = 無障礙輸出原則(auto、on、off)。 +cli.flag.default_targets.help = 未指定目標時採用的預設建置目標。 + +# 子命令說明。 +cli.subcommand.build.about = 建置資訊清單中定義的目標(預設)。 +cli.subcommand.build.long_about = 建置所要求的目標;若未指定,則採用資訊清單的預設目標。 +cli.subcommand.clean.about = 透過 Ninja 移除建置產物。 +cli.subcommand.clean.long_about = 產生暫存的 Ninja 檔案,接著執行 `ninja -t clean`。 +cli.subcommand.graph.about = 輸出建置相依性圖。預設格式為 DOT。 +cli.subcommand.graph.long_about = 將剖析後的 Netsuke 資訊清單投影為正規的建置圖,並寫成 Graphviz DOT;加上 `--html` 時則寫成自足的 HTML 頁面。使用 `--output <檔案>` 寫入檔案;`-` 會寫入標準輸出。 +cli.subcommand.generate.about = 產生 Ninja 資訊清單但不執行 Ninja。 +cli.subcommand.generate.long_about = 將產生的 Ninja 資訊清單寫入標準輸出,或寫入以 `--output` 選定的檔案。 + +# build 子命令選項的說明文字。 +cli.subcommand.build.flag.targets.help = 要建置的目標(省略時採用資訊清單的預設值)。 + +# graph 子命令選項的說明文字。 +cli.subcommand.graph.flag.html.help = 將圖算繪為自足的 HTML 頁面,而非 DOT。 +cli.subcommand.graph.flag.output.help = 將圖產物寫入檔案;標準輸出請使用 `-`。 + +# generate 子命令選項的說明文字。 +cli.subcommand.generate.flag.output.help = 將產生的 Ninja 資訊清單寫入檔案,而非標準輸出。 + +# 命令列驗證錯誤。 +cli.validation.jobs.invalid_number = { $value } 不是有效的數字。 +cli.validation.jobs.out_of_range = 工作數必須介於 { $min } 與 { $max } 之間。 +cli.validation.scheme.empty = 通訊協定不得為空。 +cli.validation.scheme.invalid_start = 通訊協定「{ $scheme }」必須以 ASCII 字母開頭。 +cli.validation.scheme.invalid = 無效的通訊協定「{ $scheme }」。 +cli.validation.locale.empty = 地區設定標記不得為空。 +cli.validation.locale.invalid = 無效的地區設定標記「{ $locale }」。 +cli.validation.color.invalid = 無效的色彩原則「{ $value }」。有效值:auto、always、never。 +cli.validation.emoji.invalid = 無效的表情符號原則「{ $value }」。有效值:auto、always、never。 +cli.validation.progress.invalid = 無效的進度原則「{ $value }」。有效值:auto、always、never。 +cli.validation.accessibility.invalid = 無效的無障礙原則「{ $value }」。有效值:auto、on、off。 +cli.validation.config.expected_object = 命令列的值本應序列化為物件,卻得到 { $value }。 + +# Clap 的錯誤訊息。 +clap-error-missing-argument = 缺少必要的引數:{ $argument } +clap-error-missing-subcommand = 缺少子命令。可用的選項:{ $valid_subcommands } +clap-error-unknown-argument = 未知的引數:{ $argument } +clap-error-invalid-value = { $argument } 的值無效:{ $value } +clap-error-invalid-subcommand = 未知的子命令:{ $subcommand } +# 注意:value-validation 的措辭與 invalid-value 不同,以便區分自訂驗證器的 +# 失敗(ErrorKind::ValueValidation)與型別不符(ErrorKind::InvalidValue)。 +clap-error-value-validation = { $argument } 驗證失敗:{ $value } + +# 執行期的錯誤與脈絡。 +runner.manifest.not_found = 在 { $directory } 中找不到資訊清單「{ $manifest_name }」。 +runner.manifest.not_found.help = 請確認資訊清單存在,或以正確的路徑指定 `--file`。 +runner.manifest.path_missing_name = 資訊清單路徑「{ $path }」沒有檔名。 +runner.manifest.path_utf8 = 資訊清單路徑「{ $path }」不是有效的 UTF-8。 +runner.manifest.directory_utf8 = 資訊清單目錄路徑「{ $path }」不是有效的 UTF-8。 +runner.manifest.directory_label = 目錄 `{ $directory }` +runner.manifest.current_directory_label = 目前的目錄 +runner.context.network_policy = 無法建立網路原則。 +runner.context.load_manifest = 無法載入 { $path } 的資訊清單。 +runner.context.serialise_manifest = 無法序列化資訊清單。 +runner.context.build_graph = 無法依資訊清單建立圖。 +runner.context.generate_ninja = 無法產生 Ninja 資訊清單。 +runner.context.render_graph = 無法算繪圖產物。 + +runner.io.create_temp_file = 無法建立暫存的 Ninja 檔案。 +runner.io.write_temp_ninja = 無法寫入暫存的 Ninja 檔案。 +runner.io.flush_temp_ninja = 無法清空暫存 Ninja 檔案的緩衝區。 +runner.io.sync_temp_ninja = 無法同步暫存的 Ninja 檔案。 +runner.io.create_parent_dir = 無法建立上層目錄 { $path }。 +runner.io.create_ninja_file = 無法在 { $path } 建立 Ninja 檔案。 +runner.io.write_ninja_file = 無法寫入 { $path } 的 Ninja 檔案。 +runner.io.flush_ninja_file = 無法清空 { $path } Ninja 檔案的緩衝區。 +runner.io.sync_ninja_file = 無法同步 { $path } 的 Ninja 檔案。 +runner.io.open_ambient_dir = 無法開啟周邊目錄。 +runner.io.no_existing_ancestor = { $path } 沒有既有的上層目錄。 +runner.io.derive_relative_path = 無法推導 Ninja 的相對路徑。 +runner.io.non_utf8_path = 不支援非 UTF-8 的路徑(路徑:{ $path })。 +runner.io.write_stdout = 無法將 Ninja 資訊清單寫入標準輸出。 +runner.io.flush_stdout = 無法清空標準輸出的緩衝區。 + +# 資訊清單診斷。 +manifest.parse = 資訊清單剖析失敗。 +manifest.structure_error = 資訊清單在 { $name } 處有結構錯誤:{ $details } +manifest.yaml.parse = 第 { $line } 行第 { $column } 列發生 YAML 剖析錯誤:{ $details } +manifest.yaml.label = 無效的 YAML +manifest.yaml.hint.tabs = YAML 不允許定位字元;縮排請使用空白。 +manifest.yaml.hint.list_item = YAML 清單項目必須以「-」開頭並正確縮排。 +manifest.yaml.hint.expected_colon = 這看起來是對應項目;索引鍵後缺少「:」。 +manifest.yaml.hint.mapping_values = YAML 對應在「:」之後需要一個值(或巢狀區塊)。 +manifest.yaml.hint.invalid_token = YAML 記號無效或出乎意料。 +manifest.yaml.hint.escape = 請逸出反斜線,或移除無效的逸出序列。 +manifest.env.missing = 未設定必要的環境變數「{ $name }」。 +manifest.env.invalid_utf8 = 環境變數「{ $name }」含有無效的 UTF-8。 +manifest.vars.not_object = 資訊清單的 `vars` 必須是對應或物件。 +manifest.read_failed = 無法讀取 { $path } 的資訊清單。 +manifest.resolve_workspace_root = 無法判定工作區的根目錄。 +manifest.workspace_non_utf8 = 工作區根路徑「{ $path }」不是有效的 UTF-8。 +manifest.path_non_utf8 = 資訊清單「{ $manifest }」的路徑不是有效的 UTF-8:{ $path }。 +manifest.path_missing_name = 資訊清單路徑「{ $path }」沒有檔名。 +manifest.open_workspace_failed = 無法為資訊清單 { $manifest } 開啟工作區 { $workspace }。 +manifest.foreach.not_iterable = `foreach` 運算式無法逐一走訪。 +manifest.foreach.serialise_item = 無法序列化 `foreach` 的元素。 +manifest.when.empty = `when` 運算式不得為空。 +manifest.when.eval_error = 無法求值 `when` 運算式「{ $expr }」。 +manifest.when.template_error = 無法算繪 `when` 範本「{ $expr }」。 +manifest.target.vars_not_object = 目標的 `vars` 必須是物件,卻得到 { $value }。 +manifest.vars.entry_not_object = 資訊清單的 `vars` 項目必須是物件。 +manifest.field_not_string = 欄位「{ $field }」必須是字串。 +manifest.expression.parse_error = 無法剖析 { $name } 運算式。 +manifest.expression.eval_error = 無法求值 { $name } 運算式。 + +# 資訊清單巨集的診斷。 +manifest.macro.signature_missing_identifier = 巨集簽章缺少識別碼。 +manifest.macro.signature_missing_params = 巨集簽章缺少參數。 +manifest.macro.compile_failed = 無法編譯巨集 { $name }。 +manifest.macro.sequence_invalid = 巨集必須定義為名稱對範本的對應。 +manifest.macro.register_failed = 無法註冊資訊清單中的巨集。 +manifest.macro.not_initialised = 巨集環境尚未初始化。 +manifest.macro.caller_invalid = 巨集的呼叫端必須是字串。 +manifest.macro.template_load_failed = 無法載入巨集範本。 +manifest.macro.init_failed = 無法初始化巨集環境。 +manifest.macro.missing = 缺少巨集 { $name }。 + +# 資訊清單的 glob 錯誤。 +manifest.glob.unmatched_brace = 無效的 glob 樣式「{ $pattern }」:位置 { $position } 的「{ $character }」沒有配對。 +manifest.glob.invalid_pattern = 無效的 glob 樣式「{ $pattern }」:{ $detail }。 +manifest.glob.unknown_pattern_error = 未知的樣式錯誤。 +manifest.glob.io_failed = 對「{ $pattern }」執行 glob 失敗:{ $detail }。 +manifest.glob.unknown_io_error = 未知的輸入輸出錯誤。 + +# 中介表示法的錯誤。 +ir.rule_not_found = 找不到目標「{ $target }」所參照的規則「{ $rule }」。 +ir.multiple_rules = 目標「{ $target }」必須只參照一條規則,卻得到 { $rules }。 +ir.empty_rule = 目標「{ $target }」必須參照一條規則。 +ir.duplicate_outputs = 偵測到重複的輸出:{ $outputs }。 +ir.circular_dependency = 偵測到循環相依:{ $cycle }。 +ir.action_serialisation = 無法序列化動作:{ $details }。 +ir.invalid_command = 命令中的插值無效:{ $snippet }。 + +# Ninja 產生錯誤。 +ninja_gen.missing_action = 缺少建置邊所參照的動作「{ $id }」。 +ninja_gen.format = 無法格式化 Ninja 資訊清單的輸出。 + +# 主機樣式驗證。 +host_pattern.empty = 主機樣式不得為空。 +host_pattern.contains_scheme = 主機樣式「{ $pattern }」不得含有 URL 通訊協定。 +host_pattern.contains_slash = 主機樣式「{ $pattern }」不得含有「/」。 +host_pattern.missing_suffix = 主機樣式「{ $pattern }」必須在「*.」之後帶有字尾。 +host_pattern.empty_label = 主機樣式「{ $pattern }」含有空白標籤。 +host_pattern.invalid_chars = 主機樣式「{ $pattern }」含有無效字元。 +host_pattern.invalid_label_edge = 主機樣式「{ $pattern }」的標籤不得以「-」開頭或結尾。 +host_pattern.label_too_long = 主機樣式「{ $pattern }」含有超過 63 個字元的標籤。 +host_pattern.too_long = 主機樣式「{ $pattern }」超出 255 個字元的上限。 + +# 網路原則。 +network_policy.scheme.empty = 通訊協定不得為空。 +network_policy.scheme.invalid = 通訊協定「{ $scheme }」含有無效字元。 +network_policy.allowlist.empty = 主機允許清單不得為空。 +network_policy.scheme.not_allowed = 不允許使用通訊協定「{ $scheme }」。 +network_policy.missing_host = URL 缺少主機。 +network_policy.host.blocked = 主機「{ $host }」已被原則封鎖。 +network_policy.host.not_allowlisted = 主機「{ $host }」不在允許清單中。 + +# 標準函式庫設定。 +stdlib.config.default_fetch_cache_invalid = fetch 快取的預設路徑必須是相對路徑。 +stdlib.config.default_which_cache_invalid = which 快取的預設容量必須為正數。 +stdlib.config.workspace_root_absolute = 工作區的根路徑必須是絕對路徑。 +stdlib.config.fetch_response_limit_positive = fetch 的回應上限必須為正數。 +stdlib.config.command_output_limit_positive = 命令輸出的擷取上限必須為正數。 +stdlib.config.command_stream_limit_positive = 命令的串流上限必須為正數。 +stdlib.config.which_cache_capacity_positive = which 快取的容量必須為正數。 +stdlib.config.skip_dir_empty = 略過目錄的項目不得為空。 +stdlib.config.skip_dir_navigation = 略過目錄的項目不得含有「..」。 +stdlib.config.skip_dir_separator = 略過目錄的項目不得含有路徑分隔字元。 +stdlib.config.fetch_cache_empty = fetch 快取的路徑不得為空。 +stdlib.config.fetch_cache_not_relative = fetch 快取的路徑必須是相對路徑,卻得到 { $path }。 +stdlib.config.fetch_cache_escapes = fetch 快取的路徑不得逸出工作區:{ $path }。 +stdlib.config.open_workspace_root = 無法將目前的目錄開啟為 stdlib 工作區的根目錄。 +stdlib.config.resolve_cwd = 無法將目前的目錄判定為 stdlib 工作區的根目錄。 +stdlib.config.cwd_non_utf8 = 目前的目錄含有非 UTF-8 的部分:{ $path }。 + +# fetch 輔助函式的診斷。 +stdlib.fetch.url_invalid = 無效的 URL「{ $url }」:{ $details }。 +stdlib.fetch.disallowed = 不允許使用 URL「{ $url }」:{ $details }。 +stdlib.fetch.failed = 無法取得「{ $url }」:{ $details }。 +stdlib.fetch.cache_read_failed = 無法讀取快取項目「{ $name }」:{ $details }。 +stdlib.fetch.cache_open_failed = 無法開啟快取項目「{ $name }」:{ $details }。 +stdlib.fetch.response_read_failed = 無法讀取來自「{ $url }」的回應:{ $details }。 +stdlib.fetch.response_buffer_overflow = 讀取「{ $url }」時緩衝區溢位。 +stdlib.fetch.cache_write_failed = 無法寫入「{ $url }」的快取:{ $details }。 +stdlib.fetch.response_limit_exceeded = 來自「{ $url }」的回應超過 { $limit } 位元組的上限。 +stdlib.fetch.cache_limit_exceeded = 快取的回應「{ $name }」超過 { $limit } 位元組的上限。 +stdlib.fetch.io_failed = 對 { $path } 執行「{ $action }」失敗:{ $details }。 +stdlib.fetch.action.sync_cache = 同步 fetch 快取 +stdlib.fetch.action.create_cache_dir = 建立 fetch 快取目錄 +stdlib.fetch.action.open_cache_dir = 開啟 fetch 快取目錄 +stdlib.fetch.action.stat_cache = 查詢 fetch 快取項目資訊 +stdlib.fetch.action.open_cache_entry = 開啟 fetch 快取項目 + +# 命令輔助函式的診斷。 +stdlib.command.location = 範本「{ $template }」中的命令「{ $command }」 +stdlib.command.spawn_failed = 無法啟動 { $location }:{ $details }。 +stdlib.command.io_failed = { $location } 失敗:{ $details }。 +stdlib.command.closed_input_early = 尚未寫完命令,輸入就已關閉。 +stdlib.command.broken_pipe = 執行 { $location } 時管線中斷:{ $details }。 +stdlib.command.terminated_by_signal = { $location } 被信號終止。 +stdlib.command.exited_with_status = { $location } 以狀態 { $status } 結束。 +stdlib.command.output_limit_exceeded = { $location } 對 { $stream } 超過了 { $mode } 的 { $limit } 位元組上限。 +stdlib.command.timeout = { $location } 超過 { $seconds } 秒的時限。 +stdlib.command.exit_status_suffix = (結束狀態 { $status }) +stdlib.command.signal_suffix = (被信號終止) +stdlib.command.shell.empty = shell 命令不得為空。 +stdlib.command.grep.empty_pattern = grep 樣式不得為空。 +stdlib.command.grep.flags_not_string = grep 的旗標必須是字串。 +stdlib.command.quote.invalid = 無法為 { $arg } 加上引號:{ $details }。 +stdlib.command.quote.line_break = 含有歸位或換行字元的引數無法安全地加上引號。 +stdlib.command.input_undefined = 輸入值未定義。 +stdlib.command.tempfile.root_required = 建立命令暫存檔需要工作區的根目錄。 +stdlib.command.tempfile.create_failed = 無法建立命令暫存檔:{ $details }。 +stdlib.command.options.invalid_utf8 = 命令選項的索引鍵必須是有效的 UTF-8。 +stdlib.command.option.mode_not_string = 輸出模式必須是字串。 +stdlib.command.options.invalid_type = 命令選項必須是物件。 +stdlib.command.output.mode_unsupported = 不支援的輸出模式「{ $mode }」。 +stdlib.command.output.mode.capture = 擷取 +stdlib.command.output.mode.streaming = 串流 +stdlib.command.output.stream.stdout = stdout +stdlib.command.output.stream.stderr = stderr + +# 路徑輔助函式的診斷。 +stdlib.path.io.failed = 對 { $path } 執行「{ $action }」失敗({ $label })。 +stdlib.path.io.failed_with_detail = 對 { $path } 執行「{ $action }」失敗:{ $detail }。 +stdlib.path.io.failed_with_label_and_detail = 對 { $path } 執行「{ $action }」失敗({ $label }):{ $detail }。 +stdlib.path.io.not_found = 找不到 +stdlib.path.io.permission_denied = 權限遭拒 +stdlib.path.io.already_exists = 已經存在 +stdlib.path.io.invalid_input = 無效的輸入 +stdlib.path.io.invalid_data = 無效的資料 +stdlib.path.io.timed_out = 已逾時 +stdlib.path.io.interrupted = 已中斷 +stdlib.path.io.would_block = 將會阻擋 +stdlib.path.io.write_zero = 寫入零位元組 +stdlib.path.io.unexpected_eof = 非預期的檔案結尾 +stdlib.path.io.broken_pipe = 管線中斷 +stdlib.path.io.connection_refused = 連線遭拒 +stdlib.path.io.connection_reset = 連線遭重設 +stdlib.path.io.connection_aborted = 連線遭中止 +stdlib.path.io.not_connected = 尚未連線 +stdlib.path.io.addr_in_use = 位址已被占用 +stdlib.path.io.addr_not_available = 位址無法使用 +stdlib.path.io.out_of_memory = 記憶體不足 +stdlib.path.io.unsupported = 不支援 +stdlib.path.io.file_too_large = 檔案過大 +stdlib.path.io.resource_busy = 資源忙碌 +stdlib.path.io.executable_busy = 可執行檔忙碌 +stdlib.path.io.deadlock = 死結 +stdlib.path.io.crosses_devices = 跨越裝置 +stdlib.path.io.too_many_links = 連結過多 +stdlib.path.io.invalid_filename = 無效的檔名 +stdlib.path.io.arg_list_too_long = 引數清單過長 +stdlib.path.io.stale_handle = 失效的網路檔案控制代碼 +stdlib.path.io.storage_full = 儲存空間已滿 +stdlib.path.io.not_seekable = 無法定位 +stdlib.path.io.network_down = 網路已中斷 +stdlib.path.io.network_unreachable = 網路無法連線 +stdlib.path.io.host_unreachable = 主機無法連線 +stdlib.path.io.other = 輸入輸出錯誤 +stdlib.path.action.canonicalize = 正規化 +stdlib.path.action.open_directory = 開啟目錄 +stdlib.path.action.stat = 查詢資訊 +stdlib.path.action.read = 讀取 +stdlib.path.action.open_file = 開啟檔案 +stdlib.path.with_suffix.empty_separator = with_suffix 需要非空的分隔字元。 +stdlib.path.relative_to.mismatch = { $path } 不是相對於 { $root } 的路徑。 +stdlib.path.expanduser.unsupported = 不支援針對特定使用者展開 ~。 +stdlib.path.expanduser.no_home = 無法展開 ~:未設定任何家目錄環境變數。 +stdlib.path.contents.unsupported_encoding = 不支援的編碼「{ $encoding }」。 +stdlib.path.hash.unsupported_algorithm = 不支援的雜湊演算法「{ $algorithm }」。 +stdlib.path.hash.unsupported_algorithm_legacy = 不支援的雜湊演算法「{ $algorithm }」(請啟用特性「{ $feature }」)。 + +# 集合輔助函式的診斷。 +stdlib.collections.flatten.expected_sequence = flatten 預期序列元素,卻發現 { $kind }。 +stdlib.collections.group_by.empty_attribute = group_by 需要非空的屬性。 +stdlib.collections.group_by.unresolved = group_by 無法在型別為 { $kind } 的元素上解析「{ $attr }」。 + +# 時間輔助函式的診斷。 +stdlib.time.offset.invalid = now 的位移「{ $offset }」無效:應為「+HH:MM[:SS]」或「Z」。 +stdlib.time.timedelta.overflow = 累加 { $component } 時 timedelta 溢位。 +stdlib.time.label.weeks = 週 +stdlib.time.label.days = 天 +stdlib.time.label.hours = 小時 +stdlib.time.label.minutes = 分鐘 +stdlib.time.label.seconds = 秒 +stdlib.time.label.milliseconds = 毫秒 +stdlib.time.label.microseconds = 微秒 +stdlib.time.label.nanoseconds = 奈秒 + +# which 輔助函式的診斷。 +stdlib.which.not_found = [netsuke::jinja::which::not_found] 檢查了 { $count } 個 PATH 項目後仍找不到命令「{ $command }」。預覽:{ $preview } +stdlib.which.not_found.hint.cwd_auto = PATH 中的空白區段會被忽略;若要納入工作目錄,請使用 cwd_mode="auto"。 +stdlib.which.not_found.hint.cwd_always = 若要納入目前的目錄,請設定 cwd_mode="always"。 +stdlib.which.direct_not_found = [netsuke::jinja::which::not_found] 「{ $path }」中的命令「{ $command }」不存在或無法執行。 +stdlib.which.args_error = [netsuke::jinja::which::args] { $details } +stdlib.which.path_preview.empty = <空白> +stdlib.which.path_entry.non_utf8 = 第 { $index } 個 PATH 項目含有非 UTF-8 字元;Netsuke 需要 UTF-8 路徑。 +stdlib.which.command.empty = which 需要非空的字串。 +stdlib.which.cwd_mode.invalid = cwd_mode 必須是「auto」、「always」或「never」,卻得到「{ $mode }」。 +stdlib.which.cwd.resolve_failed = 無法判定目前的目錄:{ $details }。 +stdlib.which.cwd.non_utf8 = 目前的目錄含有非 UTF-8 的部分。 +stdlib.which.canonicalize_failed = 無法正規化「{ $path }」:{ $details }。 +stdlib.which.is_executable = 無法判斷「{ $path }」是否可執行:{ $details }。 +stdlib.which.canonicalize_non_utf8 = 正規路徑含有非 UTF-8 的部分。 +stdlib.which.workspace_non_utf8 = 解析命令「{ $command }」時,工作區路徑含有非 UTF-8 的部分:{ $path }。 +stdlib.which.walkdir_error = 解析命令時走訪工作區發生錯誤:{ $details }。 + +# 標準函式庫註冊。 +stdlib.register.open_dir = 無法為註冊 stdlib 開啟目前的目錄。 +stdlib.register.resolve_dir = 無法為註冊 stdlib 判定目前的目錄。 +stdlib.register.dir_non_utf8 = 目前的目錄含有非 UTF-8 的部分:{ $path }。 + +# 無障礙輸出模式的狀態回報。 +status.state.pending = 等待中 +status.state.running = 進行中 +status.state.done = 已完成 +status.state.failed = 已失敗 +status.stage.label = 階段 { $current }/{ $total }:{ $description } +status.stage.summary = [{ $state }] { $label } +status.stage.summary_with_task = [{ $state }] { $label }({ $task_progress }) +status.task.progress_label = 工作 { $current }/{ $total } +status.task.progress_update = { $task }:{ $description } +status.stage.manifest_ingestion = 正在讀取資訊清單檔案 +status.stage.initial_yaml_parsing = 正在剖析 YAML 文件 +status.stage.template_expansion = 正在展開範本指示詞 +status.stage.final_rendering = 正在反序列化並算繪資訊清單的值 +status.stage.ir_generation_validation = 正在建立並驗證相依性圖 +status.stage.ninja_synthesis = 正在合成 Ninja 建置計畫 +status.stage.ninja_synthesis_execute = 正在合成 Ninja 計畫並執行 { $tool } +status.stage.graph_rendering = 正在算繪圖產物 +status.stage.graph_rendering_with_tool = 正在算繪 { $tool } +status.complete = { $tool } 已完成。 +status.timing.summary_header = 各階段耗時摘要: +status.timing.stage_line = - { $label }:{ $duration } +status.timing.total_line = 管線總耗時:{ $duration } +status.tool.build = 建置 +status.tool.clean = 清理 +status.tool.graph = 圖 +status.tool.graph_html = 圖(HTML) +status.tool.generate = 產生 + +# 圖的 HTML 算繪文字。 +graph.html.title = Netsuke 建置圖 +graph.html.heading = Netsuke 建置圖 +graph.html.description = 由 Netsuke 算繪的建置圖 +graph.html.outline.summary = 目標與相依性(文字大綱) +graph.html.outline.no_inputs = 沒有輸入 +graph.html.noscript.notice = JavaScript 已停用。上方的文字大綱即完整的圖;其後為 DOT 原始碼。 + +# 無障礙輸出的語意前置詞。 +semantic.prefix.error = 錯誤: +semantic.prefix.warning = 警告: +semantic.prefix.success = 成功: +semantic.prefix.info = 資訊: +semantic.prefix.timing = 耗時: +semantic.prefix.rendered = {"{"}symbol{"}"} {"{"}label{"}"} + +# 供譯者參考的複數形式範例。 +# 中文沒有文法上的複數變化,因此 CLDR 只有 `other` 一個類別。 +example.files_processed = { $count -> + *[other] 已處理 { $count } 個檔案。 +} + +example.errors_found = { $count -> + [0] 未發現錯誤。 + *[other] 發現 { $count } 個錯誤。 +} diff --git a/scripts/generate-release-help.sh b/scripts/generate-release-help.sh index 529cfd52a..910adede5 100755 --- a/scripts/generate-release-help.sh +++ b/scripts/generate-release-help.sh @@ -9,6 +9,10 @@ set -euo pipefail fallback_date="1970-01-01" +# Release help artefacts are generated in the source locale only. The binary +# embeds every catalogue and translates at run time, so a translated manual +# page would add per-locale release assets without adding reach. This is the +# policy stated in the users' guide; change both together. locale="en-US" build_id="${RELEASE_HELP_BUILD_ID:-${GITHUB_RUN_ID:-local}-${GITHUB_RUN_ATTEMPT:-0}}" correlation_id="${RELEASE_HELP_CORRELATION_ID:-${build_id}-release-help}" diff --git a/src/cli_localization.rs b/src/cli_localization.rs index 608d3591d..1ac1c22af 100644 --- a/src/cli_localization.rs +++ b/src/cli_localization.rs @@ -1,15 +1,16 @@ //! Locale-aware helpers for CLI messaging. //! -//! Provides Fluent-backed localizers with an English fallback and -//! consumer-provided Spanish translations to validate localization support. +//! Builds Fluent-backed localizers from the catalogue registry in +//! [`crate::locale_catalogues`], layering the requested locale over the +//! English source catalogue so any message a translation has not yet covered +//! still renders. Catalogue selection is by exact tag with the registry's +//! documented fallback rules, so region and script variants stay distinct. +use crate::locale_catalogues::{self as locales, LocaleCatalogue}; use ortho_config::LanguageIdentifier; use ortho_config::{FluentLocalizer, FluentLocalizerBuilder, Localizer, NoOpLocalizer}; use std::str::FromStr; -const NETSUKE_EN_US: &str = include_str!("../locales/en-US/messages.ftl"); -const NETSUKE_ES_ES: &str = include_str!("../locales/es-ES/messages.ftl"); - struct LayeredLocalizer { primary: Box, fallback: Box, @@ -38,7 +39,7 @@ fn parse_locale_identifier(locale: &str) -> Option { } fn build_en_localizer() -> Box { - match FluentLocalizer::with_en_us_defaults([NETSUKE_EN_US]) { + match FluentLocalizer::with_en_us_defaults([locales::source_catalogue().resource()]) { Ok(localizer) => Box::new(localizer) as Box, Err(err) => { tracing::warn!(error = %err, "failed to load default localization resources"); @@ -49,21 +50,110 @@ fn build_en_localizer() -> Box { fn build_consumer_localizer( builder: FluentLocalizerBuilder, + tag: &'static str, resource: &'static str, ) -> Option> { - builder + match builder .with_consumer_resources([resource]) .disable_defaults() .try_build() - .ok() - .map(|localizer| Box::new(localizer) as Box) + { + Ok(localizer) => Some(Box::new(localizer) as Box), + Err(err) => { + // The build-time audit checks key parity but not Fluent syntax, so + // a malformed catalogue first shows up here. Silence would look + // like the locale simply having no translations. + tracing::warn!( + locale = tag, + error = %err, + "failed to load locale catalogue; falling back to the source locale" + ); + None + } + } +} + +/// Build a localizer for `catalogue`, layered over the English source copy. +/// +/// `fallback` becomes the layered localizer's second tier. When the catalogue +/// itself fails to parse, it is handed straight back rather than rebuilt. +/// +/// The bundle is built for the catalogue's own locale, not the requested one. +/// A request resolves to a catalogue that may name a different tag — `pt-AO` +/// serves European Portuguese — and Fluent takes plural rules and number +/// formatting from the bundle's locale. Building the bundle for `pt-AO` while +/// loading the `pt-PT` catalogue would pair one locale's messages with +/// another's rules. +fn build_layered_localizer( + requested: &LanguageIdentifier, + catalogue: &'static LocaleCatalogue, + fallback: Box, +) -> Box { + let locale = parse_locale_identifier(catalogue.tag()).unwrap_or_else(|| requested.clone()); + let builder = FluentLocalizer::builder(locale); + match build_consumer_localizer(builder, catalogue.tag(), catalogue.resource()) { + Some(primary) => Box::new(LayeredLocalizer::new(primary, fallback)), + None => fallback, + } } -fn locale_language(locale: &LanguageIdentifier) -> &str { - locale.language.as_str() +/// Whether resolution abandoned the requested language for the source one. +/// +/// This is the case worth a warning: the user asked for a language Netsuke +/// does not ship and got English instead. The two ways of landing on the +/// source catalogue *without* leaving the requested language behind are ruled +/// out first, because warning about either would fire on correct input, and a +/// warning that fires on correct input trains readers to ignore it. +/// +/// The tag is compared after normalization, since `en-us` parses to `en-US`; +/// and the language is compared as well as the tag, since bare `en` — or a +/// region English ships no catalogue for — resolves to the source catalogue +/// through the fallback policy working as intended. The source language is +/// read from the tag rather than written out, so moving the source locale +/// cannot leave a stale `en` behind here. +fn fell_back_from_another_language( + locale: &LanguageIdentifier, + catalogue: &LocaleCatalogue, +) -> bool { + if catalogue.tag() != locales::SOURCE_LOCALE { + return false; + } + // `LanguageIdentifier`'s comparison against a string parses the string, so + // this is the normalized comparison without building one to throw away. + if *locale == locales::SOURCE_LOCALE { + return false; + } + locale.language.as_str() != locales::tag_language(locales::SOURCE_LOCALE) } /// Build a CLI localizer with an English fallback. +/// +/// `preferred_locale` is matched against the catalogue registry; unsupported or +/// unparseable tags fall back to the English source catalogue. +/// +/// # Examples +/// +/// The returned localizer is self-contained — nothing global is installed — +/// so lookups can be compared across independently built instances. +/// +/// ``` +/// use netsuke::cli_localization::build_localizer; +/// use netsuke::localization::keys; +/// use ortho_config::Localizer; +/// +/// // A shipped locale renders its own catalogue. +/// let french = build_localizer(Some("fr")); +/// let about = french.lookup(keys::CLI_ABOUT, None); +/// assert!(about.is_some_and(|text| text.contains("manifestes"))); +/// +/// // An unsupported locale falls back to the English source rendering. +/// let unsupported = build_localizer(Some("is-IS")); +/// let source = build_localizer(Some("en-US")); +/// assert_eq!( +/// unsupported.lookup(keys::CLI_ABOUT, None), +/// source.lookup(keys::CLI_ABOUT, None), +/// ); +/// ``` #[must_use] pub fn build_localizer(preferred_locale: Option<&str>) -> Box { let fallback = build_en_localizer(); @@ -71,15 +161,42 @@ pub fn build_localizer(preferred_locale: Option<&str>) -> Box { return fallback; }; let Some(locale) = parse_locale_identifier(preferred) else { + // A request that cannot be honoured at all: warned, not debugged, so a + // run that silently falls back to English says so without `--verbose`. + tracing::warn!( + requested = preferred, + effective = locales::SOURCE_LOCALE, + reason = "unparseable", + "locale request did not parse; falling back to the source locale" + ); return fallback; }; - if locale_language(&locale) == "es" { - let builder = FluentLocalizer::builder(locale); - if let Some(primary) = build_consumer_localizer(builder, NETSUKE_ES_ES) { - return Box::new(LayeredLocalizer::new(primary, fallback)); - } + let catalogue = locales::resolve_catalogue(&locale); + if fell_back_from_another_language(&locale, catalogue) { + // Asked for something specific and got English. That is the case a + // user would report as a bug, so it has to be visible by default. + tracing::warn!( + requested = preferred, + effective = locales::SOURCE_LOCALE, + reason = "unsupported", + "no catalogue for the requested locale; falling back to the source locale" + ); + return fallback; } - - fallback + // A resolution that landed on a real catalogue is routine; the detail is + // only wanted when tracing the choice. + tracing::debug!( + requested = preferred, + effective = catalogue.tag(), + "resolved locale catalogue" + ); + if catalogue.tag() == locales::SOURCE_LOCALE { + return fallback; + } + build_layered_localizer(&locale, catalogue, fallback) } + +#[cfg(test)] +#[path = "cli_localization_tracing_tests.rs"] +mod tracing_tests; diff --git a/src/cli_localization_tracing_tests.rs b/src/cli_localization_tracing_tests.rs new file mode 100644 index 000000000..8607ec7a3 --- /dev/null +++ b/src/cli_localization_tracing_tests.rs @@ -0,0 +1,251 @@ +//! Tests for locale resolution and catalogue-load observability. +//! +//! These assert the events themselves rather than the rendered output, because +//! the fallback is deliberately invisible to a caller: an unresolvable locale +//! and a malformed catalogue both render English. The event is the only signal +//! that either happened, so losing it would make "why is this in English?" +//! unanswerable from a log. + +use super::*; +use crate::test_tracing_capture::with_test_subscriber; +use anyhow::{Context, Result, ensure}; +use rstest::rstest; +use tracing_subscriber::filter::LevelFilter; + +/// Run `test` with a capturing subscriber and return the emitted events. +fn capture(test: impl FnOnce() -> T) -> (T, Vec) { + with_test_subscriber(LevelFilter::TRACE, |captured| { + let value = test(); + (value, captured.snapshot()) + }) +} + +/// Return the first captured event containing `needle`. +fn find_event<'a>(events: &'a [String], needle: &str) -> Result<&'a String> { + events + .iter() + .find(|event| event.contains(needle)) + .with_context(|| format!("expected an event containing {needle:?}, got {events:?}")) +} + +/// A tag that cannot parse as BCP 47 must say so, and name the tag it dropped. +/// +/// Callers normalize tags before this point, so an unparseable one means the +/// normalization was bypassed; the event has to carry the offending value or +/// there is nothing to debug from. +#[rstest] +#[case("not a locale")] +#[case("!!")] +fn an_unparseable_locale_reports_why_it_was_dropped(#[case] requested: &str) -> Result<()> { + let (_, events) = capture(|| build_localizer(Some(requested))); + + let event = find_event(&events, "locale request did not parse")?; + ensure!( + event.contains(requested), + "event must name the requested tag {requested:?}, got {event}" + ); + ensure!( + event.contains("unparseable"), + "event must carry reason=\"unparseable\", got {event}" + ); + ensure!( + event.contains(locales::SOURCE_LOCALE), + "event must name the effective locale, got {event}" + ); + Ok(()) +} + +/// A tag that parses but ships no catalogue of its own resolves through the +/// fallback rules, and the event records both ends of that decision. +#[test] +fn a_resolved_locale_reports_requested_and_effective_tags() -> Result<()> { + let (_, events) = capture(|| build_localizer(Some("zh-TW"))); + + let event = find_event(&events, "resolved locale catalogue")?; + ensure!( + event.contains("zh-TW"), + "event must name the requested tag, got {event}" + ); + ensure!( + event.contains("zh-Hant"), + "event must name the effective catalogue, got {event}" + ); + Ok(()) +} + +/// A catalogue that fails to parse must be reported with its tag and error. +/// +/// The build-time audit checks key parity but not Fluent syntax, so a malformed +/// catalogue first shows up here. Silence would be indistinguishable from the +/// locale simply having no translations. +#[test] +fn a_malformed_catalogue_reports_its_tag_and_error() -> Result<()> { + // `= not a message` is junk to the Fluent parser: an entry with no + // identifier. Fed through the same seam production uses. + let malformed = "= not a message\n"; + let locale = parse_locale_identifier("fr").context("fr must parse as a language identifier")?; + let builder = FluentLocalizer::builder(locale); + + let (built, events) = capture(|| build_consumer_localizer(builder, "fr", malformed)); + + ensure!( + built.is_none(), + "a malformed catalogue must not yield a localizer" + ); + let event = find_event(&events, "failed to load locale catalogue")?; + ensure!( + event.contains("fr"), + "event must name the offending locale, got {event}" + ); + // The rendered error itself, not merely a field named `error`: the field + // name would match even if the value were empty, and the value is the part + // a reader debugs from. `failed to parse … resources for` is the + // `FluentLocalizerError::Parser` rendering. + ensure!( + event.contains("failed to parse") && event.contains("resources for fr"), + "event must carry the rendered parse error, got {event}" + ); + Ok(()) +} + +/// The well-formed path must stay quiet: a warning per shipped locale would +/// train readers to ignore the one that matters. +#[test] +fn a_well_formed_catalogue_reports_no_failure() -> Result<()> { + let (_, events) = capture(|| build_localizer(Some("fr"))); + + ensure!( + !events + .iter() + .any(|event| event.contains("failed to load locale catalogue")), + "a shipped catalogue must load without warning, got {events:?}" + ); + Ok(()) +} + +/// A fallback-resolved request must use the catalogue's locale, not its own. +/// +/// `pt-AO` ships no catalogue and resolves to `pt-PT`. Fluent reads plural +/// rules from the bundle's locale, so building the bundle for `pt-AO` while +/// loading `pt-PT` messages would pair one locale's text with another's rules. +/// Rendering identically to a direct `pt-PT` request is what shows they agree. +#[rstest] +#[case("pt-AO", "pt-PT")] +#[case("es-MX", "es-419")] +#[case("zh-TW", "zh-Hant")] +fn a_fallback_resolved_request_renders_as_its_catalogue( + #[case] requested: &str, + #[case] catalogue_tag: &str, +) -> Result<()> { + let via_fallback = build_localizer(Some(requested)); + let via_catalogue = build_localizer(Some(catalogue_tag)); + let via_source = build_localizer(Some(locales::SOURCE_LOCALE)); + + for count in [0_i64, 1, 2, 5] { + let mut args = ortho_config::LocalizationArgs::new(); + args.insert("count", fluent_bundle::FluentValue::from(count)); + let fallback_text = via_fallback.lookup( + crate::localization::keys::EXAMPLE_FILES_PROCESSED, + Some(&args), + ); + let catalogue_text = via_catalogue.lookup( + crate::localization::keys::EXAMPLE_FILES_PROCESSED, + Some(&args), + ); + ensure!( + fallback_text == catalogue_text, + "{requested} must render as {catalogue_tag} for count {count}: {fallback_text:?} vs {catalogue_text:?}" + ); + // Agreement alone would also hold if both fell through to English, so + // this is what shows the requested catalogue was actually loaded. + let source_text = via_source.lookup( + crate::localization::keys::EXAMPLE_FILES_PROCESSED, + Some(&args), + ); + ensure!( + fallback_text != source_text, + "{requested} rendered the English source rather than {catalogue_tag} for count {count}: {fallback_text:?}" + ); + ensure!( + fallback_text.is_some_and(|text| !text.trim().is_empty()), + "{requested} rendered nothing for count {count}" + ); + } + Ok(()) +} + +/// An unsupported locale must be visible at the level a normal run uses. +/// +/// The startup filter is `WARN` when JSON mode is off, so a fallback reported +/// only at `DEBUG` would be invisible without `--verbose` — a run would render +/// English with nothing said about it. These assert the level, not just the +/// event, because that is the part that decides visibility. +#[rstest] +// A tag that parses but ships no catalogue, and whose language ships none. +#[case("is-IS")] +// A tag that cannot parse at all. +#[case("not a locale")] +fn an_english_fallback_is_reported_at_warn(#[case] requested: &str) -> Result<()> { + let (_, at_warn) = with_test_subscriber(LevelFilter::WARN, |captured| { + let localizer = build_localizer(Some(requested)); + (localizer, captured.snapshot()) + }); + + ensure!( + at_warn + .iter() + .any(|event| event.contains("falling back to the source locale")), + "a fallback to English must be reported at WARN, got {at_warn:?}" + ); + ensure!( + at_warn.iter().any(|event| event.contains(requested)), + "the event must name the requested tag {requested:?}, got {at_warn:?}" + ); + Ok(()) +} + +/// A supported locale must stay quiet at `WARN`. +/// +/// Otherwise the warning above would fire on every ordinary run and stop +/// meaning anything. +#[test] +fn a_supported_locale_warns_about_nothing() -> Result<()> { + let (_, at_warn) = with_test_subscriber(LevelFilter::WARN, |captured| { + let localizer = build_localizer(Some("fr")); + (localizer, captured.snapshot()) + }); + + ensure!( + at_warn.is_empty(), + "a shipped catalogue must not warn, got {at_warn:?}" + ); + Ok(()) +} + +/// A request that resolves within its own language is supported, not a +/// fallback. +/// +/// `en-us` normalizes to `en-US` and resolves to the source catalogue, so +/// warning about it would report a supported request as unsupported — and a +/// warning that fires on correct input trains readers to ignore it. Bare `en` +/// is the same case reached by a different route: the language fallback policy +/// sends it to `en-US` deliberately, and an English speaker who asked for +/// English got English. +#[rstest] +#[case("en-US")] +#[case("en-us")] +#[case("EN-US")] +#[case("en")] +#[case("en-AU")] +fn a_source_locale_spelling_warns_about_nothing(#[case] requested: &str) -> Result<()> { + let (_, at_warn) = with_test_subscriber(LevelFilter::WARN, |captured| { + let localizer = build_localizer(Some(requested)); + (localizer, captured.snapshot()) + }); + + ensure!( + at_warn.is_empty(), + "{requested} resolves to the source catalogue and must not warn, got {at_warn:?}" + ); + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index 19199cf4e..35a60787d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ pub mod hex; pub mod host_pattern; pub mod ir; mod json_envelope; +pub mod locale_catalogues; pub mod locale_resolution; pub mod localization; pub mod manifest; diff --git a/src/locale_catalogues.rs b/src/locale_catalogues.rs new file mode 100644 index 000000000..59c654dec --- /dev/null +++ b/src/locale_catalogues.rs @@ -0,0 +1,288 @@ +//! Authoritative registry of the locale catalogues shipped with Netsuke. +//! +//! This module is the single source of truth for which locales exist. The +//! embedded Fluent resources, the build-time key audit, the `Cargo.toml` +//! `ortho_config` metadata check, and the test suite all read the registry +//! declared here rather than repeating locale lists of their own. +//! +//! Netsuke ships one catalogue per locale tag. Requests for a tag without its +//! own catalogue are resolved through deliberate fallback rules so that +//! regional and script variants which genuinely differ — `es-419` versus +//! `es-ES`, `pt-BR` versus `pt-PT`, `zh-Hans` versus `zh-Hant` — are never +//! collapsed into a single generic language catalogue. + +use ortho_config::LanguageIdentifier; + +/// Locale tag of the source catalogue, used as the ultimate fallback. +pub const SOURCE_LOCALE: &str = "en-US"; + +/// A Fluent catalogue embedded in the binary. +#[derive(Debug, Clone, Copy)] +pub struct LocaleCatalogue { + tag: &'static str, + resource: &'static str, +} + +impl LocaleCatalogue { + /// BCP 47 tag naming this catalogue, for example `pt-BR`. + /// + /// # Examples + /// + /// ``` + /// use netsuke::locale_catalogues::catalogue; + /// + /// let entry = catalogue("pt-BR").expect("pt-BR ships a catalogue"); + /// assert_eq!(entry.tag(), "pt-BR"); + /// ``` + #[must_use] + pub const fn tag(&self) -> &'static str { + self.tag + } + + /// Fluent source text embedded from `locales//messages.ftl`. + /// + /// # Examples + /// + /// ``` + /// use netsuke::locale_catalogues::catalogue; + /// + /// let entry = catalogue("fr").expect("fr ships a catalogue"); + /// // The catalogue is the FTL source itself, so it declares Netsuke's keys. + /// assert!(entry.resource().contains("cli.about")); + /// ``` + #[must_use] + pub const fn resource(&self) -> &'static str { + self.resource + } +} + +/// Declare the supported locales and embed their catalogues. +/// +/// Each tag must have a matching `locales//messages.ftl` file; the +/// `include_str!` expansion fails the build when one is missing, which keeps +/// the registry and the on-disk catalogues in step. +macro_rules! define_locales { + ($($tag:literal),+ $(,)?) => { + /// Every locale catalogue shipped with Netsuke, ordered by tag. + pub const SUPPORTED_LOCALES: &[LocaleCatalogue] = &[ + $(LocaleCatalogue { + tag: $tag, + resource: include_str!(concat!("../locales/", $tag, "/messages.ftl")), + }),+ + ]; + }; +} + +define_locales![ + "ar", "cs", "cy", "da", "de", "el", "en-GB", "en-US", "es-419", "es-ES", "fa", "fi", "fr", + "gd", "he", "hi", "hu", "id", "it", "ja", "ko", "nb", "nl", "pl", "pt-BR", "pt-PT", "ro", "ru", + "sv", "th", "tr", "uk", "vi", "zh-Hans", "zh-Hant", +]; + +/// Fallback policy for a language that ships more than one catalogue, or whose +/// requests should be redirected to a differently named catalogue. +struct LanguageFallback { + /// Language subtag the policy applies to, for example `zh`. + language: &'static str, + /// Script or region subtags mapped to a specific catalogue. + subtags: &'static [(&'static str, &'static str)], + /// Catalogue used for any other region of this language. + other_region: &'static str, + /// Catalogue used when the request names no region or script. + bare: &'static str, +} + +/// Deliberate fallback rules for ambiguous or aliased languages. +/// +/// Languages absent from this table resolve through the unique-language rule in +/// [`resolve_catalogue`], which is sufficient while they ship exactly one +/// catalogue. +const LANGUAGE_FALLBACKS: &[LanguageFallback] = &[ + LanguageFallback { + language: "en", + // British copy is the better fit for English outside the United + // States; the bare tag keeps the source locale. + subtags: &[("US", "en-US"), ("GB", "en-GB")], + other_region: "en-GB", + bare: "en-US", + }, + LanguageFallback { + language: "es", + subtags: &[("ES", "es-ES"), ("419", "es-419")], + // Spanish-speaking regions outside Spain share the Latin American + // catalogue. + other_region: "es-419", + bare: "es-ES", + }, + LanguageFallback { + language: "pt", + subtags: &[("BR", "pt-BR"), ("PT", "pt-PT")], + other_region: "pt-PT", + bare: "pt-PT", + }, + LanguageFallback { + language: "zh", + subtags: &[ + ("Hans", "zh-Hans"), + ("Hant", "zh-Hant"), + ("CN", "zh-Hans"), + ("SG", "zh-Hans"), + ("MY", "zh-Hans"), + ("TW", "zh-Hant"), + ("HK", "zh-Hant"), + ("MO", "zh-Hant"), + ], + other_region: "zh-Hans", + bare: "zh-Hans", + }, + LanguageFallback { + // Macrolanguage Norwegian resolves to the Bokmål catalogue. + language: "no", + subtags: &[], + other_region: "nb", + bare: "nb", + }, +]; + +/// Look up a catalogue by exact tag. +/// +/// No fallback is applied: a tag that ships no catalogue of its own yields +/// `None`, even when a related one exists. Use [`resolve_catalogue`] to apply +/// the registry's fallback rules. +/// +/// # Examples +/// +/// ``` +/// use netsuke::locale_catalogues::catalogue; +/// +/// assert_eq!(catalogue("zh-Hant").map(|entry| entry.tag()), Some("zh-Hant")); +/// // `zh-TW` resolves to `zh-Hant`, but does not ship a catalogue itself. +/// assert!(catalogue("zh-TW").is_none()); +/// ``` +#[must_use] +pub fn catalogue(tag: &str) -> Option<&'static LocaleCatalogue> { + SUPPORTED_LOCALES.iter().find(|entry| entry.tag == tag) +} + +/// Catalogue used when nothing better matches. +/// +/// Placeholder used only if the registry were ever built without the source +/// locale; a test asserts that this cannot happen. +const EMPTY_SOURCE: LocaleCatalogue = LocaleCatalogue { + tag: SOURCE_LOCALE, + resource: "", +}; + +/// The source catalogue, which every other locale falls back to. +/// +/// [`SOURCE_LOCALE`] is a registry member, so the fallback arms below are +/// unreachable in practice; they exist to keep this a panic-free path. +/// +/// # Examples +/// +/// ``` +/// use netsuke::locale_catalogues::{SOURCE_LOCALE, source_catalogue}; +/// +/// assert_eq!(source_catalogue().tag(), SOURCE_LOCALE); +/// assert_eq!(source_catalogue().tag(), "en-US"); +/// ``` +#[must_use] +pub fn source_catalogue() -> &'static LocaleCatalogue { + catalogue(SOURCE_LOCALE).unwrap_or(&EMPTY_SOURCE) +} + +fn fallback_for(language: &str) -> Option<&'static LanguageFallback> { + LANGUAGE_FALLBACKS + .iter() + .find(|entry| entry.language == language) +} + +/// Catalogue for a language that ships exactly one variant, for example `fr` +/// serving a request for `fr-CA`. +fn unique_language_catalogue(language: &str) -> Option<&'static LocaleCatalogue> { + let mut matches = SUPPORTED_LOCALES + .iter() + .filter(|entry| tag_language(entry.tag) == language); + let first = matches.next()?; + matches.next().is_none().then_some(first) +} + +/// The language subtag of `tag`, which is the whole tag when it carries no +/// script or region. +pub(crate) fn tag_language(tag: &str) -> &str { + tag.split('-').next().unwrap_or(tag) +} + +fn subtag_catalogue( + fallback: &LanguageFallback, + subtag: Option<&str>, +) -> Option<&'static LocaleCatalogue> { + let requested = subtag?; + fallback + .subtags + .iter() + .find(|(key, _)| *key == requested) + .and_then(|(_, tag)| catalogue(tag)) +} + +/// Resolve the catalogue serving `locale`, applying the documented fallback +/// rules and finishing at the source locale. +/// +/// An exact tag match wins. Failing that, the two remaining rules are +/// alternatives rather than successive steps: a language with a fallback +/// policy of its own resolves entirely through it — script or +/// region rule, then that language's default — and never reaches the +/// sole-catalogue lookup. Only a language absent from that table falls back to +/// its single catalogue, and [`SOURCE_LOCALE`] serves anything still +/// unmatched. +/// +/// # Examples +/// +/// ```rust +/// use netsuke::locale_catalogues::resolve_catalogue; +/// use std::str::FromStr; +/// +/// let parse = |tag: &str| { +/// ortho_config::LanguageIdentifier::from_str(tag).expect("valid language identifier") +/// }; +/// // A Latin American region resolves to the shared es-419 catalogue. +/// assert_eq!(resolve_catalogue(&parse("es-MX")).tag(), "es-419"); +/// // Spain keeps its own. +/// assert_eq!(resolve_catalogue(&parse("es-ES")).tag(), "es-ES"); +/// // A script subtag wins over the region it is paired with. +/// assert_eq!(resolve_catalogue(&parse("zh-Hant-TW")).tag(), "zh-Hant"); +/// // A language with a single catalogue serves all its regions. +/// assert_eq!(resolve_catalogue(&parse("fr-CA")).tag(), "fr"); +/// ``` +#[must_use] +pub fn resolve_catalogue(locale: &LanguageIdentifier) -> &'static LocaleCatalogue { + let language = locale.language.as_str(); + let script = locale.script.map(|script| script.to_string()); + let region = locale.region.map(|region| region.to_string()); + + if let Some(exact) = catalogue(&locale.to_string()) { + return exact; + } + if let Some(fallback) = fallback_for(language) { + return resolve_via_fallback(fallback, script.as_deref(), region.as_deref()); + } + unique_language_catalogue(language).unwrap_or_else(source_catalogue) +} + +fn resolve_via_fallback( + fallback: &LanguageFallback, + script: Option<&str>, + region: Option<&str>, +) -> &'static LocaleCatalogue { + subtag_catalogue(fallback, script) + .or_else(|| subtag_catalogue(fallback, region)) + .or_else(|| { + let tag = if region.is_some() { + fallback.other_region + } else { + fallback.bare + }; + catalogue(tag) + }) + .unwrap_or_else(source_catalogue) +} diff --git a/src/localization/mod.rs b/src/localization/mod.rs index 90d05cf3f..60a192952 100644 --- a/src/localization/mod.rs +++ b/src/localization/mod.rs @@ -8,6 +8,12 @@ pub mod keys; +/// The locale registry, which lives at the crate root so that it depends on +/// nothing: this module reaches `cli_localization` to build the default +/// localizer, and `cli_localization` reads the registry. Keeping the registry +/// here would close that loop into a cycle. +pub use crate::locale_catalogues as locales; + use ortho_config::{LocalizationArgs, Localizer}; use std::fmt; use std::sync::{Arc, OnceLock, RwLock}; diff --git a/src/main.rs b/src/main.rs index 334298b6d..3d05b2727 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,6 +35,28 @@ impl DiagMode { } } +#[path = "startup_tracing.rs"] +mod startup_tracing; + +use startup_tracing::StartupWriter; + +/// Send buffered startup diagnostics where `mode` says they belong. +/// +/// Human mode releases them to stderr; JSON mode drops them, so the diagnostic +/// document is the only thing on that stream. +fn settle_startup_diagnostics(writer: &StartupWriter, mode: DiagMode) { + if mode.is_json() { + writer.discard(); + } else if let Err(err) = writer.release_to_stderr() { + // Nothing better to do: the channel for reporting this is the one that + // just failed. + drop(writeln!( + io::stderr(), + "failed to flush startup diagnostics: {err}" + )); + } +} + fn main() -> ExitCode { let args: Vec = std::env::args_os().collect(); let env = locale_resolution::SystemEnv; @@ -48,20 +70,31 @@ fn run_with_args( system_locale: &impl locale_resolution::SystemLocale, ) -> ExitCode { let json_hint = locale_resolution::resolve_startup_json(&args, env); + // Recorded at `WARN` but written to a buffer, not to stderr. `json_hint` is + // only a hint — configuration can still turn JSON on — and the JSON + // diagnostic goes to stderr, so an event emitted now could corrupt it. + // Buffering keeps the locale fallback report without taking that risk. + let startup_writer = StartupWriter::buffering(); + init_tracing(LevelFilter::WARN, startup_writer.clone()); let localizer = startup_localizer(&args, env, system_locale); let startup_mode = DiagMode::from_json_enabled(json_hint); - let (parsed_cli, matches) = match parse_cli_or_exit(args, &localizer, startup_mode) { - Ok(parsed) => parsed, - Err(code) => return code, - }; - // Install the subscriber disabled until the effective JSON mode is known. - // Human-mode config merging repeats discovery after the filter is enabled. - init_tracing(); + let (parsed_cli, matches) = + match parse_cli_or_exit(args, &localizer, startup_mode, &startup_writer) { + Ok(parsed) => parsed, + // The buffer was settled inside, before the branch that exits. + Err(code) => return code, + }; let mode = match resolve_json_mode_or_exit(&parsed_cli, &matches, startup_mode) { Ok(mode) => mode, - Err(code) => return code, + Err(code) => { + settle_startup_diagnostics(&startup_writer, startup_mode); + return code; + } }; + // The effective mode is known here, before configuration is merged, so the + // startup warning reaches the user ahead of any configuration processing. + settle_startup_diagnostics(&startup_writer, mode); let merged_cli = match merge_cli_or_exit(&parsed_cli, &matches, mode) { Ok(merged) => merged, Err(code) => return code, @@ -87,30 +120,36 @@ static TRACING_FILTER: OnceLock> = OnceLoc /// /// JSON mode silences tracing entirely so stderr carries only the diagnostic /// document. `--verbose` selects `TRACE` because the `NETSUKE_CONFIG` lookup is -/// traced at that level; otherwise only errors surface. +/// traced at that level. +/// +/// Otherwise `WARN`: a run that falls back to English, or loads a catalogue +/// that fails to parse, reports it at that level, and `ERROR` would leave both +/// silent — which is the condition a user would report as a bug. const fn startup_filter(mode: DiagMode, verbose: bool) -> LevelFilter { if mode.is_json() { LevelFilter::OFF } else if verbose { LevelFilter::TRACE } else { - LevelFilter::ERROR + LevelFilter::WARN } } -/// Install the process-wide subscriber with a disabled reloadable level filter. +/// Install the process-wide subscriber with a reloadable level filter set to +/// `initial`. /// /// Only the first call installs; later calls are ignored so exactly one global /// subscriber exists, and the level is adjusted through [`set_tracing_filter`] -/// rather than by installing a second subscriber. Starting disabled suppresses -/// discovery events until configuration-backed JSON mode has been resolved. -fn init_tracing() { - let (filter, handle) = reload::Layer::new(LevelFilter::OFF); +/// rather than by installing a second subscriber. Events go to `writer`, which +/// buffers until the effective mode is known and then releases to stderr or +/// discards — never to stdout, so a JSON document is never interleaved. +fn init_tracing(initial: LevelFilter, writer: StartupWriter) { + let (filter, handle) = reload::Layer::new(initial); if Registry::default() .with(filter) .with( fmt::layer() - .with_writer(io::stderr) + .with_writer(writer) // Colour only a terminal; piped or redirected logs stay plain so // they remain greppable and free of escape sequences. .with_ansi(io::stderr().is_terminal()), @@ -144,10 +183,16 @@ fn parse_cli_or_exit( args: Vec, localizer: &Arc, mode: DiagMode, + startup_writer: &StartupWriter, ) -> Result<(cli::Cli, ArgMatches), ExitCode> { match cli::parse_with_localizer_from(args, localizer) { Ok(parsed) => Ok(parsed), Err(err) => { + // Every arm below terminates the process or returns, and + // `Error::exit` never returns, so the buffered startup + // diagnostics have to be settled here. Configuration is never + // read on these paths, so `mode` is the effective mode. + settle_startup_diagnostics(startup_writer, mode); if matches!( err.kind(), ErrorKind::DisplayHelp | ErrorKind::DisplayVersion @@ -213,11 +258,14 @@ fn configure_runtime( system_locale: &impl locale_resolution::SystemLocale, mode: DiagMode, ) { + // Raised before the localizer is built, so a fallback warning is both + // visible in a normal run and suppressed in JSON mode, where stderr + // carries the diagnostic document. + set_tracing_filter(startup_filter(mode, merged_cli.verbose)); + let runtime_locale = locale_resolution::resolve_runtime_locale(merged_cli, system_locale); let runtime_localizer = Arc::from(cli_localization::build_localizer(runtime_locale.as_deref())); localization::set_localizer(Arc::clone(&runtime_localizer)); - - set_tracing_filter(startup_filter(mode, merged_cli.verbose)); } fn handle_runner_error( @@ -257,3 +305,7 @@ fn render_runtime_error_json(err: &anyhow::Error) -> serde_json::Result } diagnostic_json::render_error_json(err.as_ref()) } + +#[cfg(test)] +#[path = "main_tests.rs"] +mod tests; diff --git a/src/main_tests.rs b/src/main_tests.rs new file mode 100644 index 000000000..f26b8acb3 --- /dev/null +++ b/src/main_tests.rs @@ -0,0 +1,288 @@ +//! Tests for startup diagnostics and the level they are gated by. + +use super::*; +use anyhow::{Result, ensure}; +use netsuke::localization::keys; +use rstest::rstest; +use std::sync::{Arc, Barrier, Mutex}; +use std::thread; +use tracing_subscriber::{fmt, registry::Registry}; + +/// The level a run starts reporting at, per mode. +/// +/// This is the switch that decides whether a locale fallback is ever seen, so +/// each arm is pinned rather than inferred from behaviour elsewhere. +#[rstest] +// Human, not verbose: `WARN`, so a fallback is visible without `--verbose`. +#[case(DiagMode::Human, false, LevelFilter::WARN)] +// Human, verbose: `TRACE`, because config discovery is traced at that level. +#[case(DiagMode::Human, true, LevelFilter::TRACE)] +// JSON silences tracing entirely, whatever the verbosity. +#[case(DiagMode::Json, false, LevelFilter::OFF)] +#[case(DiagMode::Json, true, LevelFilter::OFF)] +fn the_startup_filter_matches_the_mode( + #[case] mode: DiagMode, + #[case] verbose: bool, + #[case] expected: LevelFilter, +) { + assert_eq!(startup_filter(mode, verbose), expected); +} + +/// An environment that reports nothing, so `--locale` decides the outcome. +struct EmptyEnv; + +impl locale_resolution::EnvProvider for EmptyEnv { + fn var(&self, _key: &str) -> Option { + None + } +} + +/// A system locale provider that reports nothing, for the same reason. +struct NoSystemLocale; + +impl locale_resolution::SystemLocale for NoSystemLocale { + fn system_locale(&self) -> Option { + None + } +} + +/// Drive the real startup orchestration for `locale`, returning the writer and +/// what it buffered. +/// +/// This calls `startup_localizer` — the function `run_with_args` calls — rather +/// than reaching past it to `build_localizer`, so locale resolution and the +/// installed writer are both exercised. The environment and system locale are +/// injected as empty, so the outcome depends only on the `--locale` argument +/// and no process state is read. +/// +/// `run_with_args` itself is not called: it parses the command line, and clap +/// terminates the process on help, version, and usage errors, which a unit test +/// cannot survive. `tests/startup_diagnostics_tests.rs` covers those paths by +/// running the built binary. +/// +/// `startup_localizer` installs a process-global localizer, so the previous one +/// is restored before returning. +fn record_startup(locale: &str) -> Result<(StartupWriter, String)> { + let args: Vec = ["netsuke", "--locale", locale] + .into_iter() + .map(OsString::from) + .collect(); + record_startup_with(&args, &EmptyEnv) +} + +/// Run the startup orchestration over `args` and `env`, recording what it says. +/// +/// The general form behind [`record_startup`], for the tests that need the +/// locale to arrive by a route other than `--locale`. Both share the lock and +/// the restoration, which is the part that must not be reimplemented per test. +fn record_startup_with( + args: &[OsString], + env: &E, +) -> Result<(StartupWriter, String)> { + // `startup_localizer` writes the process-global localizer, so the shared + // lock is held across installation and restoration. Without it another test + // doing the same could capture this one's override as its "previous" and + // later restore the wrong value — the lock only serializes the tests that + // take it. + let _lock = test_support::localizer_test_lock() + .map_err(|error| anyhow::anyhow!("localizer test lock poisoned: {error}"))?; + let writer = StartupWriter::buffering(); + let subscriber = Registry::default() + .with(LevelFilter::WARN) + .with(fmt::layer().with_writer(writer.clone()).with_ansi(false)); + + let previous = localization::localizer(); + tracing::subscriber::with_default(subscriber, || { + drop(startup_localizer(args, env, &NoSystemLocale)); + }); + localization::set_localizer(previous); + + let recorded = String::from_utf8_lossy(&writer.buffered()).into_owned(); + Ok((writer, recorded)) +} + +/// An unsupported startup locale must be buffered by the startup orchestration. +/// +/// Icelandic ships no catalogue and its language ships none, so the run renders +/// English. The report is held in the writer at this point — not yet on stderr +/// — which is what lets it survive until the mode is known without risking a +/// JSON document. +#[test] +fn an_unsupported_startup_locale_is_recorded_before_parsing() -> Result<()> { + let (_writer, recorded) = record_startup("is-IS")?; + + ensure!( + recorded.contains("falling back to the source locale"), + "the startup path must record the fallback, got {recorded:?}" + ); + ensure!( + recorded.contains("is-IS"), + "the record must name the requested locale, got {recorded:?}" + ); + Ok(()) +} + +/// An environment reporting `NETSUKE_LOCALE`. +struct EnvWithLocale(&'static str); + +impl locale_resolution::EnvProvider for EnvWithLocale { + fn var(&self, key: &str) -> Option { + (key == "NETSUKE_LOCALE").then(|| self.0.to_owned()) + } +} + +/// The orchestration resolves the locale rather than being handed one. +/// +/// With no `--locale` argument the tag can only reach `build_localizer` through +/// `resolve_startup_locale` consulting the injected environment. A test that +/// called `build_localizer` directly would pass whatever happened here, so this +/// is what distinguishes exercising the startup path from bypassing it. +#[test] +fn the_startup_path_resolves_the_locale_from_the_environment() -> Result<()> { + let args = vec![OsString::from("netsuke")]; + let (_writer, recorded) = record_startup_with(&args, &EnvWithLocale("is-IS"))?; + + ensure!( + recorded.contains("is-IS"), + "the environment locale must reach the localizer, got {recorded:?}" + ); + Ok(()) +} + +/// Settlement empties the buffer, whichever way the mode sends it. +/// +/// The two modes differ in *where* the recorded warning goes — released to +/// stderr, or dropped — but both must leave the writer holding nothing, so the +/// startup buffer never leaks into the rest of the run. +#[rstest] +#[case(DiagMode::Human, "human mode must release the buffer to stderr")] +#[case(DiagMode::Json, "JSON mode must drop the buffer")] +fn settling_empties_the_startup_buffer( + #[case] mode: DiagMode, + #[case] expectation: &str, +) -> Result<()> { + let (writer, recorded) = record_startup("is-IS")?; + ensure!( + !recorded.is_empty(), + "expected startup to record a warning before settlement" + ); + + settle_startup_diagnostics(&writer, mode); + + ensure!(writer.buffered().is_empty(), "{expectation}"); + Ok(()) +} + +/// A supported locale records nothing, or the warning would fire on every run +/// and stop carrying information. +#[test] +fn a_supported_startup_locale_records_nothing() -> Result<()> { + let (_writer, recorded) = record_startup("fr")?; + ensure!( + recorded.is_empty(), + "a shipped catalogue must not warn at startup, got {recorded:?}" + ); + Ok(()) +} + +/// The startup orchestration installs the resolved localizer globally, and the +/// previous one is restored once the scope ends. +/// +/// `startup_localizer` mutates process-global state, so this holds the shared +/// test-localizer lock across installation, observation, and restoration. A +/// second thread emits one controlled event while the startup localizer is +/// installed, coordinated by barriers rather than timing, to show that the +/// buffered writer is shared correctly and that a concurrent emitter cannot +/// observe a half-installed state. +#[test] +fn startup_installs_and_restores_the_global_localizer() -> Result<()> { + let _lock = test_support::localizer_test_lock() + .map_err(|error| anyhow::anyhow!("localizer test lock poisoned: {error}"))?; + + let before = localization::message(keys::CLI_ABOUT).to_string(); + let writer = StartupWriter::buffering(); + let subscriber = Registry::default() + .with(LevelFilter::WARN) + .with(fmt::layer().with_writer(writer.clone()).with_ansi(false)); + + let args: Vec = ["netsuke", "--locale", "fr"] + .into_iter() + .map(OsString::from) + .collect(); + // A guard, not a manual restore at the end: every `?` and `ensure!` below + // is an early exit, and a manual restore after them would be skipped on + // any of those paths, leaving the French localizer installed for whichever + // test runs next. Installing the current localizer over itself is a no-op + // that captures it as the guard's restore target. + let previous = localization::localizer(); + let restore = localization::set_localizer_for_tests(Arc::clone(&previous)); + + // Two rendezvous: the first once the localizer is installed, the second + // once the concurrent event has been emitted. + let installed = Arc::new(Barrier::new(2)); + let emitted = Arc::new(Barrier::new(2)); + let during = Arc::new(Mutex::new(String::new())); + + let (thread_installed, thread_emitted, thread_during, thread_writer) = ( + Arc::clone(&installed), + Arc::clone(&emitted), + Arc::clone(&during), + writer.clone(), + ); + let observer = thread::spawn(move || { + thread_installed.wait(); + // Observed while the startup localizer is installed. + let rendered = localization::message(keys::CLI_ABOUT).to_string(); + if let Ok(mut slot) = thread_during.lock() { + *slot = rendered; + } + // `with_default` installs a *thread-local* subscriber, so an event + // emitted here would reach the main thread's subscriber only if this + // thread had one of its own. Installing one over a clone of the same + // writer is what makes this exercise the shared buffer rather than + // silently emit into nothing. + let observer_subscriber = Registry::default() + .with(LevelFilter::WARN) + .with(fmt::layer().with_writer(thread_writer).with_ansi(false)); + tracing::subscriber::with_default(observer_subscriber, || { + tracing::warn!(target: "concurrent", "observed during startup"); + }); + thread_emitted.wait(); + }); + + tracing::subscriber::with_default(subscriber, || { + drop(startup_localizer(&args, &EmptyEnv, &NoSystemLocale)); + installed.wait(); + emitted.wait(); + }); + + observer + .join() + .map_err(|_| anyhow::anyhow!("observer thread panicked"))?; + + let rendered_during_startup = during + .lock() + .map_err(|error| anyhow::anyhow!("observation lock poisoned: {error}"))? + .clone(); + ensure!( + rendered_during_startup != before, + "the concurrent observer must see the installed French localizer, \ + got {rendered_during_startup:?}" + ); + + let buffered = String::from_utf8_lossy(&writer.buffered()).into_owned(); + ensure!( + buffered.contains("observed during startup"), + "the concurrent thread's event must reach the shared writer, got {buffered:?}" + ); + + // Dropped explicitly so the final assertion observes the restored state; + // the guard would otherwise restore only after the assertion ran. + drop(restore); + let after = localization::message(keys::CLI_ABOUT).to_string(); + ensure!( + after == before, + "the previous localizer must be restored, got {after:?} rather than {before:?}" + ); + Ok(()) +} diff --git a/src/startup_tracing.rs b/src/startup_tracing.rs new file mode 100644 index 000000000..e6d55966c --- /dev/null +++ b/src/startup_tracing.rs @@ -0,0 +1,248 @@ +//! Startup diagnostics held until the effective output mode is known. +//! +//! Netsuke resolves its locale before it parses the command line, because +//! usage errors have to be rendered in the user's language. That ordering +//! creates a window: a locale that falls back to English is worth reporting, +//! but the JSON diagnostic document is written to stderr, and configuration can +//! still turn JSON on after the fallback has happened. Emitting immediately +//! risks corrupting that document; emitting at `OFF` loses the report. +//! +//! So startup events are written to a buffer instead of a stream. Once the +//! effective mode is settled, the buffer is either released to stderr (human +//! mode) or dropped (JSON mode), and everything after that is written straight +//! through. + +use std::io::{self, Write}; +use std::sync::{Arc, Mutex, MutexGuard, PoisonError}; + +use tracing_subscriber::fmt::MakeWriter; + +/// The most startup diagnostics that will be held before the effective mode is +/// known. +/// +/// The window is short — locale resolution, then command-line parsing — and +/// what it carries is a handful of one-line warnings. The bound exists so that +/// the size of what is buffered never depends on how much a run happens to +/// emit: without it, a pathological run could hold arbitrary bytes in memory +/// before anything decided where they belong. +/// +/// Overflow keeps the first bytes rather than the last: the earliest +/// diagnostics describe how the run was configured, which is what a reader +/// needs, and later ones are progressively less informative about the startup +/// decision. Once full, [`TRUNCATION_MARKER`] is appended once, if it fits, and +/// everything after is dropped. +const MAX_BUFFERED_BYTES: usize = 64 * 1024; + +/// Appended once when [`MAX_BUFFERED_BYTES`] is reached, so a truncated buffer +/// says so rather than appearing to be the whole of it. +const TRUNCATION_MARKER: &[u8] = b"\n[startup diagnostics truncated]\n"; + +/// Where startup diagnostics are going right now. +enum Sink { + /// Held until the effective mode is known. + Buffered(BoundedBuffer), + /// Human mode: written through to stderr. + Stderr, + /// JSON mode: discarded, so stderr carries only the diagnostic document. + Discard, +} + +/// A byte buffer that stops growing at [`MAX_BUFFERED_BYTES`]. +/// +/// Once full it records that it truncated, so the marker is appended exactly +/// once however many writes follow. +#[derive(Default)] +struct BoundedBuffer { + bytes: Vec, + truncated: bool, +} + +impl BoundedBuffer { + /// Append as much of `buf` as the bound allows. + /// + /// The first write to overflow keeps the bytes that fit, then appends the + /// truncation marker if there is room for it. Later writes are dropped. + fn append(&mut self, buf: &[u8]) { + if self.truncated { + return; + } + let remaining = MAX_BUFFERED_BYTES.saturating_sub(self.bytes.len()); + if buf.len() <= remaining { + self.bytes.extend_from_slice(buf); + return; + } + // Room for the marker is reserved rather than claimed afterwards. A + // buffer filled to exactly the bound would leave none, and the marker + // would be dropped in precisely the case it is needed. + let content_limit = MAX_BUFFERED_BYTES.saturating_sub(TRUNCATION_MARKER.len()); + if self.bytes.len() < content_limit { + let keep = content_limit.saturating_sub(self.bytes.len()); + // `get` rather than a slice index: the lint forbids slicing that + // could panic, and a short `buf` is a legitimate input here. + if let Some(head) = buf.get(..keep.min(buf.len())) { + self.bytes.extend_from_slice(head); + } + } + self.bytes.truncate(content_limit); + self.bytes.extend_from_slice(TRUNCATION_MARKER); + self.truncated = true; + } + + fn take(&mut self) -> Vec { + self.truncated = false; + std::mem::take(&mut self.bytes) + } + + #[cfg(test)] + fn as_slice(&self) -> &[u8] { + &self.bytes + } +} + +/// A writer that buffers until told where the output belongs. +/// +/// Cloned by the `fmt` layer for each event, so the sink is shared behind an +/// `Arc`; every clone observes the same state and the same buffer. +#[derive(Clone)] +pub struct StartupWriter { + sink: Arc>, +} + +impl StartupWriter { + /// A writer that holds everything written to it. + /// + /// # Examples + /// + /// ```text + /// let w = StartupWriter::buffering(); + /// warn!("locale fell back"); -> held; nothing reaches stderr + /// ``` + /// + /// Examples are shown rather than run: this module is compiled into the + /// binary, and Cargo does not run doctests for a binary target, so a + /// `rust` block would never be checked and would rot unnoticed. + #[must_use] + pub fn buffering() -> Self { + Self { + sink: Arc::new(Mutex::new(Sink::Buffered(BoundedBuffer::default()))), + } + } + + fn lock(&self) -> MutexGuard<'_, Sink> { + // A panic while formatting an event must not cascade into losing the + // rest of the diagnostics. + self.sink.lock().unwrap_or_else(PoisonError::into_inner) + } + + /// Write everything buffered to stderr, and write through from now on. + /// + /// Called when the effective mode turns out to be human. + /// + /// # Examples + /// + /// ```text + /// warn!("locale fell back"); -> held + /// w.release_to_stderr()?; -> the held bytes reach stderr, buffer emptied + /// warn!("something later"); -> written straight to stderr + /// ``` + /// + /// # Errors + /// + /// Returns the error from writing the buffered bytes to stderr. + pub fn release_to_stderr(&self) -> io::Result<()> { + let mut sink = self.lock(); + let buffered = match &mut *sink { + Sink::Buffered(buffer) => buffer.take(), + Sink::Stderr | Sink::Discard => Vec::new(), + }; + *sink = Sink::Stderr; + drop(sink); + if buffered.is_empty() { + return Ok(()); + } + io::stderr().write_all(&buffered) + } + + /// Drop everything buffered, and discard whatever follows. + /// + /// Called when the effective mode turns out to be JSON, so that stderr + /// carries only the diagnostic document. + /// + /// # Examples + /// + /// ```text + /// warn!("locale fell back"); -> held + /// w.discard(); -> the held bytes are dropped + /// warn!("something later"); -> dropped too, not re-buffered + /// ``` + pub fn discard(&self) { + let mut sink = self.lock(); + *sink = Sink::Discard; + } + + /// The bytes currently held, for tests that assert what was recorded + /// before the mode was known. + /// + /// Test-only: production code never inspects the buffer, it only decides + /// where the buffer goes. + #[cfg(test)] + #[must_use] + pub fn buffered(&self) -> Vec { + match &*self.lock() { + Sink::Buffered(buffer) => buffer.as_slice().to_vec(), + Sink::Stderr | Sink::Discard => Vec::new(), + } + } +} + +/// The per-event handle the `fmt` layer writes through. +pub struct StartupWriterHandle { + sink: Arc>, +} + +impl Write for StartupWriterHandle { + fn write(&mut self, buf: &[u8]) -> io::Result { + let mut sink = self.sink.lock().unwrap_or_else(PoisonError::into_inner); + match &mut *sink { + Sink::Buffered(buffer) => { + buffer.append(buf); + // The whole slice is reported as written even when the bound + // dropped some of it: the formatter has no recourse, and a + // short write would be reported through the channel being + // truncated. + Ok(buf.len()) + } + Sink::Stderr => { + drop(sink); + io::stderr().write(buf) + } + // Report the bytes as written: the caller has no recourse, and a + // short-write error would be reported through the very channel + // being discarded. + Sink::Discard => Ok(buf.len()), + } + } + + fn flush(&mut self) -> io::Result<()> { + let sink = self.sink.lock().unwrap_or_else(PoisonError::into_inner); + if matches!(&*sink, Sink::Stderr) { + drop(sink); + return io::stderr().flush(); + } + Ok(()) + } +} + +impl<'writer> MakeWriter<'writer> for StartupWriter { + type Writer = StartupWriterHandle; + + fn make_writer(&'writer self) -> Self::Writer { + StartupWriterHandle { + sink: Arc::clone(&self.sink), + } + } +} + +#[cfg(test)] +#[path = "startup_tracing_tests.rs"] +mod tests; diff --git a/src/startup_tracing_tests.rs b/src/startup_tracing_tests.rs new file mode 100644 index 000000000..88fa37ab4 --- /dev/null +++ b/src/startup_tracing_tests.rs @@ -0,0 +1,224 @@ +//! Tests for the buffered startup writer. +//! +//! These drive a real `fmt` layer through a scoped subscriber, so what is +//! asserted is what the layer actually writes, not a stand-in for it. + +use super::*; +use anyhow::{Result, ensure}; +use rstest::rstest; +use tracing_subscriber::{filter::LevelFilter, fmt, prelude::*, registry::Registry}; + +/// Emit `event` through a subscriber writing to `writer`. +/// +/// Scoped with `with_default` rather than installed globally, so each test gets +/// its own subscriber and they do not contend for the process-wide one. +fn emit_warning(writer: &StartupWriter, message: &'static str) { + let subscriber = Registry::default() + .with(LevelFilter::WARN) + .with(fmt::layer().with_writer(writer.clone()).with_ansi(false)); + tracing::subscriber::with_default(subscriber, || { + tracing::warn!(target: "startup", "{message}"); + }); +} + +/// A warning emitted before the mode is known must be held, not written. +#[test] +fn a_startup_warning_is_buffered_rather_than_written() -> Result<()> { + let writer = StartupWriter::buffering(); + emit_warning(&writer, "locale fell back"); + + let buffered = String::from_utf8(writer.buffered())?; + ensure!( + buffered.contains("locale fell back"), + "the event must be recorded while buffering, got {buffered:?}" + ); + Ok(()) +} + +/// After discarding, later events are dropped too — not buffered up again. +/// +/// Without this, a JSON run would accumulate every subsequent event in memory +/// and the mode decision would apply only to the startup window. +#[test] +fn events_after_discarding_are_not_buffered() -> Result<()> { + let writer = StartupWriter::buffering(); + writer.discard(); + + emit_warning(&writer, "after the decision"); + + ensure!( + writer.buffered().is_empty(), + "an event after discarding must not be retained" + ); + Ok(()) +} + +/// Releasing an empty buffer is not an error, which is the common case: most +/// runs resolve their locale without falling back. +#[test] +fn releasing_an_empty_buffer_succeeds() -> Result<()> { + let writer = StartupWriter::buffering(); + writer.release_to_stderr()?; + ensure!( + writer.buffered().is_empty(), + "an empty buffer stays empty once released" + ); + Ok(()) +} + +/// Write `bytes` straight through the writer, bypassing the tracing layer. +/// +/// The bound is a property of the writer, not of any event, so these drive it +/// directly rather than trying to provoke a large event. +fn write_raw(writer: &StartupWriter, bytes: &[u8]) -> Result { + use std::io::Write as _; + let mut handle = writer.make_writer(); + Ok(handle.write(bytes)?) +} + +/// Below the bound, everything is kept and nothing is marked. +#[test] +fn a_write_below_the_limit_is_kept_whole() -> Result<()> { + let writer = StartupWriter::buffering(); + let payload = vec![b'a'; MAX_BUFFERED_BYTES - 1]; + + let written = write_raw(&writer, &payload)?; + + ensure!(written == payload.len(), "the whole slice must be reported"); + let buffered = writer.buffered(); + ensure!(buffered == payload, "the bytes must be kept unchanged"); + ensure!( + !buffered.ends_with(TRUNCATION_MARKER), + "nothing was dropped, so nothing should be marked" + ); + Ok(()) +} + +/// Exactly at the bound is not an overflow. +#[test] +fn a_write_at_the_limit_is_kept_whole() -> Result<()> { + let writer = StartupWriter::buffering(); + let payload = vec![b'a'; MAX_BUFFERED_BYTES]; + + write_raw(&writer, &payload)?; + + let buffered = writer.buffered(); + ensure!( + buffered.len() == MAX_BUFFERED_BYTES, + "expected exactly the bound, got {}", + buffered.len() + ); + ensure!( + !buffered.ends_with(TRUNCATION_MARKER), + "a write that fits exactly must not be marked as truncated" + ); + Ok(()) +} + +/// Overflow keeps the first bytes, marks the truncation, and never exceeds the +/// bound. +#[test] +fn an_overflowing_write_keeps_the_first_bytes_and_marks_it() -> Result<()> { + let writer = StartupWriter::buffering(); + let payload = vec![b'a'; MAX_BUFFERED_BYTES + 4096]; + + let written = write_raw(&writer, &payload)?; + + ensure!( + written == payload.len(), + "dropped overflow must still report the whole slice as written" + ); + let buffered = writer.buffered(); + ensure!( + buffered.len() <= MAX_BUFFERED_BYTES, + "the buffer must not exceed its bound, got {}", + buffered.len() + ); + ensure!( + buffered.starts_with(b"aaaa"), + "the earliest bytes are the ones kept" + ); + ensure!( + buffered.ends_with(TRUNCATION_MARKER), + "an overflow must be marked" + ); + Ok(()) +} + +/// Repeated overflow adds nothing further, and marks once only. +#[test] +fn repeated_overflow_marks_once_and_grows_no_further() -> Result<()> { + let writer = StartupWriter::buffering(); + write_raw(&writer, &vec![b'a'; MAX_BUFFERED_BYTES + 1])?; + let after_first = writer.buffered(); + + for _ in 0..3 { + write_raw(&writer, b"more diagnostics that must be dropped")?; + } + let after_more = writer.buffered(); + + ensure!( + after_more == after_first, + "writes after truncation must change nothing" + ); + let marker = String::from_utf8_lossy(TRUNCATION_MARKER).into_owned(); + let rendered = String::from_utf8_lossy(&after_more).into_owned(); + ensure!( + rendered.matches(&marker).count() == 1, + "the marker must appear exactly once, found {}", + rendered.matches(&marker).count() + ); + Ok(()) +} + +/// How the buffer was filled before settlement. +#[derive(Clone, Copy)] +enum Fill { + /// One ordinary event, well within the bound. + OneEvent, + /// Enough to overflow, so the buffer is truncated and marked. + PastTheBound, +} + +/// Where settlement sends what was buffered. +#[derive(Clone, Copy)] +enum Settlement { + Release, + Discard, +} + +/// Settling empties the buffer, however it was filled and wherever it goes. +/// +/// The four combinations share one shape: fill, settle, assert empty. Written +/// out separately they differed only in which two calls they made, which is +/// duplication rather than coverage. The truncated cases matter because a +/// truncated buffer must not stay truncated for the rest of the run. +#[rstest] +#[case::release_after_one_event(Fill::OneEvent, Settlement::Release)] +#[case::discard_after_one_event(Fill::OneEvent, Settlement::Discard)] +#[case::release_after_truncation(Fill::PastTheBound, Settlement::Release)] +#[case::discard_after_truncation(Fill::PastTheBound, Settlement::Discard)] +fn settling_empties_the_buffer(#[case] fill: Fill, #[case] settlement: Settlement) -> Result<()> { + let writer = StartupWriter::buffering(); + match fill { + Fill::OneEvent => emit_warning(&writer, "locale fell back"), + Fill::PastTheBound => { + write_raw(&writer, &vec![b'a'; MAX_BUFFERED_BYTES + 1])?; + } + } + ensure!( + !writer.buffered().is_empty(), + "the buffer must hold something before settlement" + ); + + match settlement { + Settlement::Release => writer.release_to_stderr()?, + Settlement::Discard => writer.discard(), + } + + ensure!( + writer.buffered().is_empty(), + "settling must leave the buffer empty" + ); + Ok(()) +} diff --git a/test_support/src/localizer.rs b/test_support/src/localizer.rs index 87242dcfd..9a35b88b8 100644 --- a/test_support/src/localizer.rs +++ b/test_support/src/localizer.rs @@ -21,6 +21,57 @@ pub fn set_en_localizer() -> LocalizerGuard { localization::set_localizer_for_tests(Arc::from(localizer)) } +/// Records whether the test lock was still held when the localizer guard +/// began to drop. +/// +/// This is the seam that makes the drop-order invariant observable. The +/// ordering it protects has no behavioural signature under normal scheduling — +/// a waiting thread almost never lands inside the window — so a contention +/// test alone cannot distinguish correct from incorrect field order. +#[cfg(test)] +pub(crate) static LOCK_HELD_AT_RESTORE: Mutex> = Mutex::new(None); + +/// Wraps the localizer guard so the moment it drops can be observed. +/// +/// Transparent in production: the wrapper exists so that a test can ask +/// whether the lock was still held at the instant the restore began. The +/// wrapper's `Drop` body runs before its field is dropped, which is exactly +/// that instant. +pub struct RestoreProbe { + /// Held for its `Drop`, which restores the previous localizer. Never read: + /// the value has no API, only an effect at end of scope. The leading + /// underscore is what exempts it from `dead_code`, rather than an + /// expectation that would outlive any work it could be linked to. + _guard: LocalizerGuard, +} + +impl RestoreProbe { + fn new(guard: LocalizerGuard) -> Self { + Self { _guard: guard } + } +} + +impl Drop for RestoreProbe { + fn drop(&mut self) { + #[cfg(test)] + { + // `try_lock` from the thread already holding it returns + // `WouldBlock`: `std::sync::Mutex` is not reentrant. So "blocked" + // means the guard bundle still holds the lock, and "acquired" + // means the lock was released before the restore — the fault. + // Only `WouldBlock` is evidence of that: a poisoned result means + // the lock was acquirable, so counting it as held would mask the + // very release-before-restore fault this probe exists to catch. + let held = LOCALIZER_TEST_LOCK.get().is_some_and(|lock| { + matches!(lock.try_lock(), Err(std::sync::TryLockError::WouldBlock)) + }); + let mut slot = LOCK_HELD_AT_RESTORE + .lock() + .unwrap_or_else(PoisonError::into_inner); + *slot = Some(held); + } + } +} /// RAII bundle holding both the global localizer test lock and the English /// locale guard for the lifetime of a test. /// @@ -34,7 +85,11 @@ pub fn set_en_localizer() -> LocalizerGuard { /// thread install its own override and capture this test's override as its /// "previous", so that thread would later restore the wrong value. pub struct EnLocalizer { - _guard: LocalizerGuard, + // Field order is the invariant: Rust drops fields in declaration order, so + // the localizer guard must come first. It restores the process-global + // localizer, and doing that after the mutex was released would let another + // test install its own localizer into the window and have it overwritten. + _guard: RestoreProbe, _lock: MutexGuard<'static, ()>, } @@ -85,7 +140,65 @@ pub fn en_localizer() -> EnLocalizer { // poisoning the same way. let lock = localizer_test_lock().unwrap_or_else(PoisonError::into_inner); EnLocalizer { - _guard: set_en_localizer(), + _guard: RestoreProbe::new(set_en_localizer()), + _lock: lock, + } +} + +/// RAII bundle holding the localizer test lock and an arbitrary locale. +/// +/// [`EnLocalizer`] covers the common case of pinning English. Catalogue sweeps +/// need the same pairing for each locale in turn, which is what this provides. +/// +/// Obtained from [`locale_localizer`]. Dropping it restores the localizer that +/// was installed beforehand and *then* releases the shared test lock, in that +/// order — so no other test can be admitted into the window between the two and +/// have its own localizer overwritten. +/// +/// The ordering is the field declaration order, since Rust drops fields in the +/// order they are declared; see [`EnLocalizer`] for the same arrangement. +pub struct LocaleLocalizer { + _guard: RestoreProbe, + _lock: MutexGuard<'static, ()>, +} + +/// Acquire the localizer test lock and install the localizer for `locale`. +/// +/// Infallible, like [`en_localizer`] and for the same reason: a poisoned lock +/// is recovered from rather than reported, and building a localizer cannot +/// fail — an unsupported tag resolves to the English source catalogue. There +/// is no error for a caller to decide about, so returning a `Result` would +/// only oblige every call site to unwrap one that is always `Ok`. +/// +/// Dropping the returned guard restores the previously installed localizer and +/// releases the shared test lock, so locale-specific tests can run in sequence +/// without leaking state into one another. +/// +/// # Examples +/// +/// ``` +/// use netsuke::localization::{self, keys}; +/// use test_support::localizer::locale_localizer; +/// +/// let guard = locale_localizer("fr"); +/// let rendered = localization::message(keys::CLI_ABOUT).to_string(); +/// assert!(rendered.contains("Netsuke")); +/// drop(guard); // the previous localizer is restored here +/// ``` +#[must_use] +pub fn locale_localizer(locale: &str) -> LocaleLocalizer { + // Lock first, then install: the guard returned by + // `set_localizer_for_tests` captures the localizer to restore, so it must + // be created under the lock. + // Poisoning is recovered from, as `en_localizer` does and for the same + // reason: the lock orders localizer installation and nothing more, and the + // installation below re-establishes the global state unconditionally. + // Propagating instead would make one panicking test fail every later test + // that takes this lock, long after the original failure. + let lock = localizer_test_lock().unwrap_or_else(PoisonError::into_inner); + let localizer = cli_localization::build_localizer(Some(locale)); + LocaleLocalizer { + _guard: RestoreProbe::new(localization::set_localizer_for_tests(Arc::from(localizer))), _lock: lock, } } @@ -154,3 +267,7 @@ mod tests { ); } } + +#[cfg(test)] +#[path = "localizer_tests.rs"] +mod drop_order_tests; diff --git a/test_support/src/localizer_tests.rs b/test_support/src/localizer_tests.rs new file mode 100644 index 000000000..bd8130d17 --- /dev/null +++ b/test_support/src/localizer_tests.rs @@ -0,0 +1,136 @@ +//! Tests for the localizer guards' drop ordering. +//! +//! The invariant under test is not observable from a single thread: it only +//! matters when a second test is waiting for the lock. These drive that +//! contention deterministically rather than by timing. + +use super::*; +use netsuke::localization::{self, keys}; +use std::sync::mpsc; +use std::sync::{Barrier, TryLockError}; +use std::thread; + +/// Whether the globally installed localizer is currently the French one. +/// +/// Identity is not observable through `Arc`, so the rendered +/// text stands in for it: `cli.about` differs between French and the English +/// source. +fn localizer_is_french() -> bool { + localization::message(keys::CLI_ABOUT) + .to_string() + .contains("manifestes") +} + +/// The lock must not be released before the previous localizer is restored. +/// +/// A waiting thread is admitted only once the whole guard has dropped, so the +/// localizer it observes is the restored one. Were the fields declared the +/// other way round, the lock would be released first and the waiting thread +/// could be admitted into a window where the French localizer is still +/// installed. +/// +/// The barrier makes the waiter demonstrably contended before the drop begins: +/// the main thread holds the lock across it, so the waiter's `lock()` call is +/// blocked, not merely late. +/// +/// What the waiter sees is compared against the state captured *before* the +/// guard was installed, not against "not French". Restoration means putting +/// back whatever was there, and asserting a particular value instead would +/// make this test fail for a reason of its own if the process default ever +/// changed. +#[test] +fn the_lock_is_held_until_the_localizer_is_restored() { + let french_before = localizer_is_french(); + let bundle = locale_localizer("fr"); + assert!( + localizer_is_french(), + "the fixture must install the French localizer" + ); + + let barrier = Arc::new(Barrier::new(2)); + let (tx, rx) = mpsc::channel(); + let waiter_barrier = Arc::clone(&barrier); + let waiter = thread::spawn(move || { + // Signal readiness, then block on the lock the main thread still holds. + waiter_barrier.wait(); + let guard = localizer_test_lock(); + let observed_french = localizer_is_french(); + drop(guard); + // The receiver outlives this send; a closed channel would fail the + // test at `recv` rather than here. + tx.send(observed_french).ok(); + }); + + // Released only after the waiter is running and about to contend. + barrier.wait(); + // The waiter cannot hold the lock: this thread does, through `bundle`. + assert!( + matches!( + LOCALIZER_TEST_LOCK + .get() + .expect("the lock is initialized by the fixture") + .try_lock(), + Err(TryLockError::WouldBlock) + ), + "the fixture must still hold the lock before it is dropped" + ); + + drop(bundle); + + let observed_french = rx.recv().expect("the waiting thread reports what it saw"); + waiter.join().expect("the waiting thread completes"); + assert_eq!( + observed_french, french_before, + "a thread admitted after the drop must see the restored localizer, \ + not the one the guard installed" + ); +} + +/// The guard restores the previous localizer when it drops. +/// +/// Sequential, not nested: `LOCALIZER_TEST_LOCK` is a plain `Mutex` and is not +/// reentrant, so acquiring a second fixture inside the first deadlocks. +#[test] +fn dropping_the_guard_restores_the_previous_localizer() { + let french_before = localizer_is_french(); + { + let _french = locale_localizer("fr"); + assert!(localizer_is_french(), "the fixture installs French"); + } + assert_eq!( + localizer_is_french(), + french_before, + "dropping the fixture restores the previous localizer" + ); +} + +/// The lock must still be held at the instant the localizer is restored. +/// +/// This is the deterministic proof of the field-drop order. A contention test +/// cannot supply one: with the fields declared the wrong way round the window +/// between releasing the lock and restoring the localizer is a few +/// instructions wide, so a waiting thread virtually never lands in it and the +/// test passes on broken code. +/// +/// `RestoreProbe::drop` runs immediately before the localizer guard it wraps is +/// dropped, and records whether the lock was held at that moment. Correct order +/// leaves the lock held; the wrong order has already released it. +#[test] +fn the_lock_is_still_held_when_the_restore_begins() { + *LOCK_HELD_AT_RESTORE + .lock() + .unwrap_or_else(PoisonError::into_inner) = None; + + drop(locale_localizer("fr")); + + let observed = *LOCK_HELD_AT_RESTORE + .lock() + .unwrap_or_else(PoisonError::into_inner); + assert_eq!( + observed, + Some(true), + "the localizer guard must be dropped while the lock is still held; \ + `false` means the lock was released first, so another test could be \ + admitted before the previous localizer was restored" + ); +} diff --git a/tests/build_l10n_audit_rules_tests.rs b/tests/build_l10n_audit_rules_tests.rs new file mode 100644 index 000000000..255a502e4 --- /dev/null +++ b/tests/build_l10n_audit_rules_tests.rs @@ -0,0 +1,190 @@ +//! Tests for the localization audit's comparison rules. +//! +//! Split from `build_l10n_parser_tests.rs` to keep both files within the +//! repository's 400-line limit. That file covers the parsers that read the +//! catalogues and the Cargo metadata; this one covers what the audit does with +//! their results — which keys are missing, orphaned, or interpolate the wrong +//! variables, and how the resulting failure reads. + +use std::collections::BTreeSet; + +use anyhow::{Result, anyhow, ensure}; +use rstest::rstest; + +#[path = "../build_l10n_audit/compare.rs"] +mod compare; +#[path = "../build_l10n_audit/ftl.rs"] +mod ftl; + +/// Build a `MessageVariables` map from `(key, variables)` pairs. +fn catalogue(entries: &[(&str, &[&str])]) -> ftl::MessageVariables { + entries + .iter() + .map(|(key, vars)| { + ( + (*key).to_owned(), + vars.iter().map(|v| (*v).to_owned()).collect(), + ) + }) + .collect() +} + +fn declared(keys: &[&str]) -> BTreeSet { + keys.iter().map(|key| (*key).to_owned()).collect() +} + +/// Audit `entries` for a locale against a one-key source, returning the +/// failure message, or `None` when the catalogue is clean. +fn audit( + declared_keys: &[&str], + source: &[(&str, &[&str])], + entries: &[(&str, &[&str])], +) -> Option { + let findings = compare::audit_catalogue( + "xx", + &declared(declared_keys), + &catalogue(source), + &catalogue(entries), + ); + (!findings.is_clean()).then(|| compare::build_error_message(std::slice::from_ref(&findings))) +} + +const SOURCE: &[(&str, &[&str])] = &[("a.key", &["path"]), ("b.key", &[])]; +const DECLARED: &[&str] = &["a.key", "b.key"]; + +/// A catalogue matching the declared keys and the source variables passes. +#[test] +fn a_matching_catalogue_is_clean() -> Result<()> { + let message = audit(DECLARED, SOURCE, SOURCE); + ensure!(message.is_none(), "expected no findings, got {message:?}"); + Ok(()) +} + +/// Catalogues that each break one audit rule against `SOURCE`. +const OMITS_A_DECLARED_KEY: &[(&str, &[&str])] = &[("a.key", &["path"])]; +const CARRIES_AN_UNDECLARED_KEY: &[(&str, &[&str])] = + &[("a.key", &["path"]), ("b.key", &[]), ("c.key", &[])]; +const DROPS_A_VARIABLE: &[(&str, &[&str])] = &[("a.key", &[]), ("b.key", &[])]; +const INVENTS_A_VARIABLE: &[(&str, &[&str])] = &[("a.key", &["path"]), ("b.key", &["name"])]; +const RENAMES_A_VARIABLE: &[(&str, &[&str])] = &[("a.key", &["route"]), ("b.key", &[])]; + +#[rstest] +#[case(OMITS_A_DECLARED_KEY, "missing in xx: b.key")] +#[case(CARRIES_AN_UNDECLARED_KEY, "orphaned in xx: c.key")] +#[case( + DROPS_A_VARIABLE, + "variable mismatch in xx: a.key (expected $path, found none)" +)] +#[case( + INVENTS_A_VARIABLE, + "variable mismatch in xx: b.key (expected none, found $name)" +)] +#[case( + RENAMES_A_VARIABLE, + "variable mismatch in xx: a.key (expected $path, found $route)" +)] +fn the_audit_rejects(#[case] entries: &[(&str, &[&str])], #[case] expected: &str) -> Result<()> { + let message = audit(DECLARED, SOURCE, entries) + .ok_or_else(|| anyhow!("expected the audit to report a finding"))?; + ensure!( + message.contains(expected), + "expected a finding mentioning {expected:?}, got {message:?}" + ); + Ok(()) +} + +/// One catalogue can fail several rules at once, and the message names each. +#[test] +fn every_rule_is_reported_together() -> Result<()> { + const BREAKS_EVERY_RULE: &[(&str, &[&str])] = &[("a.key", &[]), ("c.key", &[])]; + let entries = BREAKS_EVERY_RULE; + let message = audit(DECLARED, SOURCE, entries) + .ok_or_else(|| anyhow!("expected the audit to report findings"))?; + for expected in [ + "missing in xx: b.key", + "orphaned in xx: c.key", + "variable mismatch in xx: a.key", + ] { + ensure!( + message.contains(expected), + "expected {expected:?} in {message:?}" + ); + } + Ok(()) +} + +/// The audit's failure message is user-visible build output, so its exact shape +/// is pinned rather than probed a substring at a time. +/// +/// One locale carrying all three categories at once is the case a substring +/// assertion covers least well: it says nothing about ordering, grouping, or +/// how the sections read together, which is what a maintainer actually sees +/// when a build fails. The inputs are fixed literals and every collection the +/// message renders is a `BTree*`, so the output is deterministic — no paths, +/// temporary directories, or error wrappers appear in it. +#[test] +fn the_failure_message_reports_every_category() -> Result<()> { + const SOURCE_KEYS: &[(&str, &[&str])] = &[("a.key", &["path"]), ("b.key", &["count"])]; + // Drops `a.key`, renames `b.key`'s variable, and adds an undeclared key. + const DRIFTED: &[(&str, &[&str])] = &[("b.key", &["tally"]), ("z.orphan", &[])]; + + let message = audit(&["a.key", "b.key"], SOURCE_KEYS, DRIFTED) + .ok_or_else(|| anyhow!("expected the drifted catalogue to be rejected"))?; + + // Kept alongside the snapshot: these say which categories must appear, so + // an accidental snapshot acceptance cannot quietly drop one. + ensure!( + message.contains("missing in xx: a.key"), + "expected the missing key, got {message}" + ); + ensure!( + message.contains("orphaned in xx: z.orphan"), + "expected the orphaned key, got {message}" + ); + ensure!( + message.contains("variable mismatch in xx: b.key"), + "expected the variable mismatch, got {message}" + ); + + insta::assert_snapshot!(message); + Ok(()) +} + +/// The parser and the rules compose: a catalogue read from FTL text is audited +/// the same way one built by hand is. +/// +/// The other tests here construct `MessageVariables` directly, which keeps them +/// focused on the rules but leaves the seam between the two halves untested. +/// This drives real catalogue text through `ftl::parse_catalogue` and into +/// `audit_catalogue`, so a change to how variables are collected shows up as an +/// audit result rather than only as a parser result. +#[test] +fn a_parsed_catalogue_is_audited_by_the_same_rules() -> Result<()> { + let source = ftl::parse_catalogue("a.key = Uses { $path }\nb.key = Plain text\n") + .map_err(|error| anyhow!("{error}"))?; + // Renames the variable and drops `b.key`, adding an undeclared key instead. + let drifted = ftl::parse_catalogue("a.key = Utilise { $chemin }\nz.orphan = Extra\n") + .map_err(|error| anyhow!("{error}"))?; + + let findings = + compare::audit_catalogue("fr", &declared(&["a.key", "b.key"]), &source, &drifted); + ensure!( + !findings.is_clean(), + "the drifted catalogue must be rejected" + ); + + let message = compare::build_error_message(std::slice::from_ref(&findings)); + ensure!( + message.contains("missing in fr: b.key"), + "expected the dropped key, got {message}" + ); + ensure!( + message.contains("orphaned in fr: z.orphan"), + "expected the undeclared key, got {message}" + ); + ensure!( + message.contains("variable mismatch in fr: a.key (expected $path, found $chemin)"), + "expected the renamed variable, got {message}" + ); + Ok(()) +} diff --git a/tests/build_l10n_audit_tests.rs b/tests/build_l10n_audit_tests.rs new file mode 100644 index 000000000..ef77ebebc --- /dev/null +++ b/tests/build_l10n_audit_tests.rs @@ -0,0 +1,222 @@ +//! End-to-end tests for the build-time localization audit. +//! +//! The unit tests in `build_l10n_parser_tests.rs` cover the audit's rules +//! against synthetic input. This file runs the real orchestration over the +//! checked-in tree — the registry, `Cargo.toml`'s metadata, the declared keys, +//! and all 35 catalogues — so that drift in any of them fails the test suite +//! rather than only the next clean build. +//! +//! The audit lives in a build script, which is not a test target, so its +//! modules are included by path. `locale_catalogues` comes with them because +//! the audit reads the registry through `crate::locale_catalogues`. + +use anyhow::{Result, bail, ensure}; +use rstest::{fixture, rstest}; +use std::fs; +use std::path::{Path, PathBuf}; +use tempfile::TempDir; + +// The audit reads the registry through `crate::locale_catalogues`. Re-exporting +// the library's module under that path satisfies it without compiling a second +// copy of the registry into this crate — which is also why no dead-code +// expectation is needed for it. +pub use netsuke::locale_catalogues; + +#[path = "../build_l10n_audit/mod.rs"] +mod build_l10n_audit; + +use build_l10n_audit::{audit_localization_keys, audit_localization_keys_in, catalogue_path}; +use locale_catalogues::{LocaleCatalogue, SUPPORTED_LOCALES}; + +fn repository_root() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) +} + +/// The audit must pass against the tree as committed. +/// +/// This is the test that fails when a catalogue loses a key, gains an orphan, +/// or changes an interpolation variable, and when `Cargo.toml`'s locale list +/// drifts from the registry. +#[test] +fn the_audit_passes_over_the_checked_in_tree() -> Result<()> { + if let Err(error) = audit_localization_keys_in(&repository_root()) { + bail!("the committed tree must pass its own localization audit: {error}"); + } + Ok(()) +} + +/// Copy the repository's audit inputs into `destination`. +/// +/// Only the files the audit reads are staged, so a mutation test perturbs a +/// copy and never the working tree. +fn stage_audit_inputs(destination: &Path) -> Result<()> { + let root = repository_root(); + fs::create_dir_all(destination.join("src/localization"))?; + fs::copy(root.join("Cargo.toml"), destination.join("Cargo.toml"))?; + fs::copy( + root.join("src/localization/keys.rs"), + destination.join("src/localization/keys.rs"), + )?; + for entry in SUPPORTED_LOCALES { + let relative = Path::new("locales").join(entry.tag()); + fs::create_dir_all(destination.join(&relative))?; + fs::copy( + root.join(&relative).join("messages.ftl"), + destination.join(&relative).join("messages.ftl"), + )?; + } + Ok(()) +} + +/// A staged copy of the audit inputs, ready to be perturbed. +/// +/// Fallible, per house style: staging is arrangement, so its failures are +/// propagated for the test body to surface with `?` rather than panicking +/// inside the fixture. +#[fixture] +fn staged_tree() -> Result { + let staged = TempDir::new()?; + stage_audit_inputs(staged.path())?; + Ok(staged) +} + +/// The staged copy must itself pass, or the mutation cases below would prove +/// nothing: a failure could mean the staging was incomplete rather than that +/// the mutation was detected. +#[rstest] +fn the_staged_copy_reproduces_a_passing_audit( + #[from(staged_tree)] staged_tree_res: Result, +) -> Result<()> { + let staged = staged_tree_res?; + if let Err(error) = audit_localization_keys_in(staged.path()) { + bail!("staged inputs must reproduce a passing audit: {error}"); + } + Ok(()) +} + +/// Each way the tree can drift must fail the audit. +/// +/// Every case perturbs one input and asserts the audit rejects it, which is +/// what makes the passing test above meaningful rather than vacuous. +#[rstest] +#[case::a_catalogue_loses_a_key("missing in fr", &|root: &Path| { + let catalogue = root.join("locales/fr/messages.ftl"); + let text = fs::read_to_string(&catalogue)?; + let kept: Vec<&str> = text + .lines() + .filter(|line| !line.starts_with("cli.about")) + .collect(); + ensure!(kept.len() < text.lines().count(), "expected a cli.about message to drop"); + fs::write(&catalogue, kept.join("\n"))?; + Ok(()) +})] +#[case::a_catalogue_gains_an_orphan("orphaned in de", &|root: &Path| { + let catalogue = root.join("locales/de/messages.ftl"); + let mut text = fs::read_to_string(&catalogue)?; + text.push_str("\nnetsuke.not.a.declared.key = Verwaist\n"); + fs::write(&catalogue, text)?; + Ok(()) +})] +#[case::a_catalogue_changes_a_variable("variable mismatch in it", &|root: &Path| { + let catalogue = root.join("locales/it/messages.ftl"); + let text = fs::read_to_string(&catalogue)?; + let mutated = text.replacen("{ $path }", "{ $percorso }", 1); + ensure!(mutated != text, "expected a $path interpolation to rewrite"); + fs::write(&catalogue, mutated)?; + Ok(()) +})] +#[case::the_metadata_drops_a_locale("does not match the locale registry", &|root: &Path| { + let manifest = root.join("Cargo.toml"); + let text = fs::read_to_string(&manifest)?; + let mutated = text.replacen("\"zh-Hant\",", "", 1).replacen("\"zh-Hant\"", "", 1); + ensure!(mutated != text, "expected zh-Hant in the metadata list"); + fs::write(&manifest, mutated)?; + Ok(()) +})] +#[case::a_key_declaration_is_added("missing in", &|root: &Path| { + let keys = root.join("src/localization/keys.rs"); + let text = fs::read_to_string(&keys)?; + let mutated = text.replacen( + "define_keys! {", + "define_keys! {\n UNSHIPPED_KEY => \"netsuke.unshipped.key\",", + 1, + ); + ensure!(mutated != text, "expected the define_keys! macro to rewrite"); + fs::write(&keys, mutated)?; + Ok(()) +})] +fn the_audit_rejects_a_drifting_tree( + #[from(staged_tree)] staged_tree_res: Result, + #[case] expected: &str, + #[case] mutate: &dyn Fn(&Path) -> Result<()>, +) -> Result<()> { + let staged = staged_tree_res?; + mutate(staged.path())?; + + let message = match audit_localization_keys_in(staged.path()) { + Ok(()) => bail!("the audit accepted a tree it should have rejected"), + Err(error) => error.to_string(), + }; + ensure!( + message.contains(expected), + "expected the failure to mention {expected:?}, got {message}" + ); + Ok(()) +} + +/// Every registry entry must have a catalogue the audit can actually read. +/// +/// `include_str!` already fails the build for a missing file, but it embeds at +/// compile time; this checks the on-disk path the audit reads at build time +/// resolves for the same set of tags. +#[test] +fn every_registry_tag_has_a_readable_catalogue() -> Result<()> { + let root = repository_root(); + for entry in SUPPORTED_LOCALES { + let path = root.join("locales").join(entry.tag()).join("messages.ftl"); + ensure!( + path.is_file(), + "locale {} has no catalogue at {}", + entry.tag(), + path.display() + ); + } + ensure!( + SUPPORTED_LOCALES + .iter() + .map(LocaleCatalogue::tag) + .any(|tag| tag == "en-US"), + "the registry must contain the source locale" + ); + Ok(()) +} + +/// `catalogue_path` is what `build.rs` emits its `rerun-if-changed` directives +/// from, so its shape is a contract: a path relative to the repository root. +#[test] +fn the_catalogue_path_is_repository_relative() -> Result<()> { + let path = catalogue_path("pt-BR"); + ensure!( + path == Path::new("locales/pt-BR/messages.ftl"), + "expected a repository-relative catalogue path, got {}", + path.display() + ); + Ok(()) +} + +/// The build script's own entry point must pass from the repository root. +/// +/// `audit_localization_keys` reads paths relative to the working directory, +/// which Cargo sets to the manifest directory for integration tests — the same +/// directory it uses when running the build script. +#[test] +fn the_build_script_entry_point_passes_from_the_manifest_directory() -> Result<()> { + ensure!( + std::env::current_dir()? == repository_root(), + "this test assumes Cargo runs it from the manifest directory" + ); + if let Err(error) = audit_localization_keys() { + bail!("the build script's entry point must pass over the committed tree: {error}"); + } + Ok(()) +} diff --git a/tests/build_l10n_keys_tests.rs b/tests/build_l10n_keys_tests.rs new file mode 100644 index 000000000..e77f8e890 --- /dev/null +++ b/tests/build_l10n_keys_tests.rs @@ -0,0 +1,269 @@ +//! Tests for the `define_keys!` parser used by the build-time localization +//! audit. +//! +//! The parser lives in the build script, which `cargo test` does not build as +//! a test target, so the module is included here by path. Only +//! `extract_key_constants` is reachable, which is the surface `build.rs` uses; +//! the scanner is exercised through it. + +#[path = "../build_l10n_audit/keys.rs"] +mod keys; + +use std::collections::BTreeSet; + +use anyhow::{Result, anyhow, bail, ensure}; +use rstest::rstest; + +/// Wrap `entries` in a `define_keys!` invocation and extract its keys. +fn extract(entries: &str) -> Result> { + extract_source(&format!("define_keys! {{\n{entries}\n}}\n")) +} + +fn extract_source(source: &str) -> Result> { + keys::extract_key_constants(source).map_err(|error| anyhow!("{error}")) +} + +/// Extract from a `define_keys!` body expected to fail, returning the message. +fn extraction_error(entries: &str) -> Result { + let source = format!("define_keys! {{\n{entries}\n}}\n"); + match keys::extract_key_constants(&source) { + Ok(extracted) => bail!("expected extraction to fail, got {extracted:?}"), + Err(error) => Ok(error.to_string()), + } +} + +fn key_set(keys: &[&str]) -> BTreeSet { + keys.iter().map(|key| (*key).to_owned()).collect() +} + +#[rstest] +// A plain entry, the shape the real macro uses. +#[case("CLI_ABOUT => \"cli.about\",", &["cli.about"])] +// Several entries, including one whose value escapes a quote. +#[case( + "A => \"first.key\",\n B => \"second.key\",", + &["first.key", "second.key"] +)] +#[case(r#"A => "quoted\"key","#, &["quoted\"key"])] +// A backslash escape other than a quote keeps the escaped character. +#[case(r#"A => "back\\slash","#, &["back\\slash"])] +fn regular_string_literals_yield_their_keys( + #[case] entries: &str, + #[case] expected: &[&str], +) -> Result<()> { + let extracted = extract(entries)?; + ensure!( + extracted == key_set(expected), + "expected {expected:?}, got {extracted:?}" + ); + Ok(()) +} + +#[rstest] +// A raw string with no hashes. +#[case("A => r\"raw.key\",", &["raw.key"])] +// One hash, so the value may contain a quote. +#[case("A => r#\"raw \"quoted\" key\"#,", &["raw \"quoted\" key"])] +// Two hashes, so the value may contain a quote-hash pair. +#[case("A => r##\"raw \"# key\"##,", &["raw \"# key"])] +// A raw string does not process escapes. +#[case("A => r\"back\\slash\",", &["back\\slash"])] +fn raw_string_literals_yield_their_keys( + #[case] entries: &str, + #[case] expected: &[&str], +) -> Result<()> { + let extracted = extract(entries)?; + ensure!( + extracted == key_set(expected), + "expected {expected:?}, got {extracted:?}" + ); + Ok(()) +} + +/// Commented-out entries must not contribute keys, or a key removed by +/// commenting it out would still be demanded of every catalogue. +#[rstest] +#[case( + "A => \"live.key\",\n // B => \"commented.key\",", + &["live.key"] +)] +#[case( + "A => \"live.key\",\n /* B => \"commented.key\", */", + &["live.key"] +)] +// A block comment spanning lines. +#[case( + "A => \"live.key\",\n /*\n B => \"commented.key\",\n */", + &["live.key"] +)] +// A line comment as the final line, with no trailing newline inside the body. +#[case("A => \"live.key\", // trailing", &["live.key"])] +fn comments_are_skipped(#[case] entries: &str, #[case] expected: &[&str]) -> Result<()> { + let extracted = extract(entries)?; + ensure!( + extracted == key_set(expected), + "expected {expected:?}, got {extracted:?}" + ); + Ok(()) +} + +#[rstest] +// An unterminated regular string. +#[case("A => \"unterminated,", "unterminated string literal")] +// An unterminated raw string. +#[case("A => r#\"unterminated,", "unterminated raw string literal")] +// A raw marker with no opening quote. +#[case("A => r#x\",", "raw string literal missing opening quote")] +// A value that is not a string literal at all. +#[case("A => 42,", "expected string literal after define_keys! =>")] +fn malformed_literals_are_rejected(#[case] entries: &str, #[case] expected: &str) -> Result<()> { + let message = extraction_error(entries)?; + ensure!( + message.contains(expected), + "expected an error mentioning {expected:?}, got {message:?}" + ); + Ok(()) +} + +/// Byte strings carry bytes rather than text, so they cannot name a Fluent +/// message. A raw byte string is reported specifically; a plain one fails +/// earlier, when the mandatory `r` marker is found missing. +#[rstest] +#[case("A => br\"bytes\",", "byte string literals are not supported")] +#[case("A => br#\"bytes\"#,", "byte string literals are not supported")] +#[case("A => b\"bytes\",", "expected string literal after define_keys! =>")] +fn byte_string_literals_are_rejected(#[case] entries: &str, #[case] expected: &str) -> Result<()> { + let message = extraction_error(entries)?; + ensure!( + message.contains(expected), + "expected an error mentioning {expected:?}, got {message:?}" + ); + Ok(()) +} + +#[rstest] +// No macro at all. +#[case("fn main() {}\n", "define_keys! macro not found")] +// The macro name present but no body. +#[case("define_keys!\n", "define_keys! macro body is missing '{'")] +// An unclosed body. +#[case( + "define_keys! {\n A => \"a\",\n", + "define_keys! macro body is missing '}'" +)] +// A body with no entries. +#[case("define_keys! {\n}\n", "no localization keys found")] +fn malformed_macro_invocations_are_rejected( + #[case] source: &str, + #[case] expected: &str, +) -> Result<()> { + let message = match keys::extract_key_constants(source) { + Ok(extracted) => bail!("expected extraction to fail, got {extracted:?}"), + Err(error) => error.to_string(), + }; + ensure!( + message.contains(expected), + "expected an error mentioning {expected:?}, got {message:?}" + ); + Ok(()) +} + +/// Braces inside comments and string literals are not source, so the body +/// scan must step over them. Before it did, a doc comment mentioning `}` or a +/// key whose value contained one truncated the declared key set or failed the +/// build outright. +#[rstest] +// An unbalanced brace in a line comment. +#[case("A => \"a.key\",\n // { stray brace", "a.key")] +// An unbalanced brace in a doc comment, which is how this would really arrive. +#[case("/// Braces like } appear in prose.\n A => \"a.key\",", "a.key")] +// An unbalanced brace in a block comment. +#[case("/* } */\n A => \"a.key\",", "a.key")] +// An unbalanced brace inside a key's value. +#[case("A => \"{\",", "{")] +// An unbalanced brace inside a raw string value. +#[case("A => r#\"a}key\"#,", "a}key")] +fn braces_in_comments_and_literals_do_not_end_the_body( + #[case] entries: &str, + #[case] expected: &str, +) -> Result<()> { + let extracted = extract(entries)?; + ensure!( + extracted.contains(expected), + "expected the body scan to reach {expected:?}, got {extracted:?}" + ); + Ok(()) +} + +/// A body that genuinely never closes is still an error. +#[test] +fn an_unterminated_body_is_still_reported() -> Result<()> { + let source = "define_keys! {\n A => \"a.key\",\n"; + let message = match extract_source(source) { + Ok(keys) => bail!("expected an unterminated body error, got {keys:?}"), + Err(error) => error.to_string(), + }; + ensure!( + message.contains("define_keys! macro body is missing '}'"), + "expected the body scan to report an unterminated body, got {message:?}" + ); + Ok(()) +} + +/// Macro-shaped text that is not the invocation must not be mistaken for it. +/// +/// A doc comment naming `define_keys!`, or a string containing it, previously +/// captured the search: extraction started from the mention and read the wrong +/// text as the body. +#[rstest] +// Named in a line doc comment above the real invocation. +#[case("/// See define_keys! for the declaration format.\n")] +// Named in a block comment. +#[case("/* define_keys! { NOT => \"not.a.key\", } */\n")] +// Quoted in a string constant, braces and all. +#[case("const SAMPLE: &str = \"define_keys! { NOT => \\\"not.a.key\\\", }\";\n")] +fn a_mention_of_the_macro_does_not_displace_the_invocation(#[case] preamble: &str) -> Result<()> { + let source = format!("{preamble}define_keys! {{\n A => \"a.key\",\n}}\n"); + let extracted = extract_source(&source)?; + ensure!( + extracted == key_set(&["a.key"]), + "expected only the real invocation's key, got {extracted:?}" + ); + Ok(()) +} + +/// Trivia between the macro name and its delimiter must not be mistaken for +/// the delimiter, and nested block comments must close at the outer `*/`. +#[rstest] +// A brace inside a comment between the name and the real delimiter. +#[case("define_keys! /* { */ {\n A => \"a.key\",\n}\n")] +// A line comment between the name and the delimiter. +#[case("define_keys! // opens below\n{\n A => \"a.key\",\n}\n")] +// A nested block comment before the invocation. +#[case("/* outer /* inner */ still a comment */\ndefine_keys! {\n A => \"a.key\",\n}\n")] +// A macro whose name merely ends with the one being looked for. +#[case("other_define_keys! { NOT => \"not.a.key\", }\ndefine_keys! {\n A => \"a.key\",\n}\n")] +fn the_real_invocation_is_selected(#[case] source: &str) -> Result<()> { + let extracted = extract_source(source)?; + ensure!( + extracted == key_set(&["a.key"]), + "expected only the real invocation's key, got {extracted:?}" + ); + Ok(()) +} + +/// The real macro body is the contract this parser exists to read. +#[test] +fn the_repository_macro_parses() -> Result<()> { + let extracted = extract_source(include_str!("../src/localization/keys.rs"))?; + ensure!( + extracted.contains("cli.about"), + "expected the repository keys to include cli.about" + ); + ensure!( + extracted.len() > 300, + "expected the repository to declare over 300 keys, got {}", + extracted.len() + ); + Ok(()) +} diff --git a/tests/build_l10n_parser_tests.rs b/tests/build_l10n_parser_tests.rs new file mode 100644 index 000000000..a50a1463d --- /dev/null +++ b/tests/build_l10n_parser_tests.rs @@ -0,0 +1,390 @@ +//! Tests for the build audit's Fluent and Cargo-metadata parsers. +//! +//! Both live in the build script, which `cargo test` does not build as a test +//! target, so the modules are included here by path. Neither depends on the +//! library crate, so each compiles standalone. + +#[path = "../build_l10n_audit/ftl.rs"] +mod ftl; +#[path = "../build_l10n_audit/metadata.rs"] +mod metadata; + +use std::collections::BTreeSet; + +use anyhow::{Result, anyhow, bail, ensure}; +use rstest::rstest; + +// ---------------------------------------------------------------- FTL parser + +/// Parse `source` as a catalogue. +fn parse(source: &str) -> Result { + ftl::parse_catalogue(source).map_err(|error| anyhow!("{error}")) +} + +/// The variables the parser found for `key`. +fn variables_of(parsed: &ftl::MessageVariables, key: &str) -> Result> { + let found = parsed + .get(key) + .ok_or_else(|| anyhow!("{key} was not parsed; got {:?}", parsed.keys()))?; + Ok(found.iter().cloned().collect()) +} + +fn names(expected: &[&str]) -> Vec { + expected.iter().map(|name| (*name).to_owned()).collect() +} + +#[test] +fn message_identifiers_are_collected() -> Result<()> { + let parsed = parse("first = one\nsecond = two\n")?; + let ids: BTreeSet<&str> = parsed.keys().map(String::as_str).collect(); + ensure!( + ids == BTreeSet::from(["first", "second"]), + "expected both identifiers, got {ids:?}" + ); + Ok(()) +} + +/// Comments carry translator context, including `$` examples, and must not +/// contribute either identifiers or variables. +/// +/// Both cases begin a line, which is what makes them comments. An indented +/// `#` is a continuation instead, whatever it looks like; see +/// [`an_indented_hash_line_continues_the_message`] and +/// [`an_indented_line_before_any_message_contributes_nothing`]. +#[rstest] +#[case("# a comment mentioning { $ghost }\nkey = value\n")] +#[case("## a group comment { $ghost }\nkey = value\n")] +fn comments_contribute_nothing(#[case] source: &str) -> Result<()> { + let parsed = parse(source)?; + let ids: BTreeSet<&str> = parsed.keys().map(String::as_str).collect(); + ensure!(ids == BTreeSet::from(["key"]), "got {ids:?}"); + ensure!( + variables_of(&parsed, "key")?.is_empty(), + "a comment leaked a variable into the message" + ); + Ok(()) +} + +/// An indented line with no message above it has nothing to continue. +/// +/// It reaches the continuation branch rather than the comment branch — the +/// parser tests indentation first — and is dropped for want of a message to +/// attach to. The outcome matches a comment's, but the route does not, so it +/// is asserted separately rather than filed among the comment cases where it +/// would look like evidence the comment branch had run. +#[test] +fn an_indented_line_before_any_message_contributes_nothing() -> Result<()> { + let parsed = parse(" # an indented line with { $ghost }\nkey = value\n")?; + let ids: BTreeSet<&str> = parsed.keys().map(String::as_str).collect(); + ensure!(ids == BTreeSet::from(["key"]), "got {ids:?}"); + ensure!( + variables_of(&parsed, "key")?.is_empty(), + "an orphaned continuation leaked a variable into the next message" + ); + Ok(()) +} + +#[rstest] +// One variable on the value line. +#[case("key = uses { $path }\n", &["path"])] +// Several, including a repeat, which the set collapses. +#[case("key = { $min } to { $max } and { $min }\n", &["max", "min"])] +// A variable on an indented continuation line. +#[case("key = opening\n continued with { $detail }\n", &["detail"])] +// A `select` expression: the selector and the variants both count. +#[case( + "key = { $count ->\n [one] one { $item }\n *[other] many { $item }\n}\n", + &["count", "item"] +)] +// Underscores and digits are part of a variable name; a bare `$` is not. +#[case("key = { $task_progress } and $ alone\n", &["task_progress"])] +fn variables_are_collected(#[case] source: &str, #[case] expected: &[&str]) -> Result<()> { + let parsed = parse(source)?; + let found = variables_of(&parsed, "key")?; + ensure!( + found == names(expected), + "expected {expected:?}, got {found:?}" + ); + Ok(()) +} + +/// A blank line does not end a pattern; the next entry does. +/// +/// This previously asserted the opposite. Fluent permits blank lines inside a +/// multiline pattern, so an indented line after one is still a continuation of +/// the message above, and its variables belong to that message. Reading it the +/// old way dropped variables the audit is meant to compare. +#[test] +fn an_indented_line_after_a_blank_continues_the_message() -> Result<()> { + let parsed = parse("key = value\n\n continued { $ghost }\nother = second\n")?; + ensure!( + variables_of(&parsed, "key")? == ["ghost"], + "the continuation's variable belongs to the message above the blank line" + ); + ensure!( + variables_of(&parsed, "other")?.is_empty(), + "the next entry starts a new message" + ); + Ok(()) +} + +/// Terms are reusable fragments that code never references, so the audit +/// ignores them rather than demanding a matching key. +#[test] +fn terms_are_ignored() -> Result<()> { + let parsed = parse("-brand = Netsuke\nkey = value\n")?; + let ids: BTreeSet<&str> = parsed.keys().map(String::as_str).collect(); + ensure!(ids == BTreeSet::from(["key"]), "got {ids:?}"); + Ok(()) +} + +/// An empty catalogue is a mistake worth failing on: it would make every +/// declared key look missing. +#[rstest] +#[case("")] +#[case("# only comments\n")] +fn catalogues_without_messages_are_rejected(#[case] source: &str) -> Result<()> { + match ftl::parse_catalogue(source) { + Ok(parsed) => bail!("expected a parse failure, got {parsed:?}"), + Err(error) => ensure!( + error.to_string().contains("no Fluent messages found"), + "unexpected error: {error}" + ), + } + Ok(()) +} + +// ----------------------------------------------------------- Cargo metadata + +fn metadata_locales(manifest: &str) -> Option> { + metadata::parse_metadata_locales(manifest) +} + +const TABLE: &str = "[package.metadata.ortho_config]\nroot_type = \"x\"\n"; + +#[test] +fn a_single_line_array_is_read() -> Result<()> { + let manifest = format!("{TABLE}locales = [\"en-US\", \"fr\"]\n"); + let found = metadata_locales(&manifest) + .ok_or_else(|| anyhow!("expected the locales key to be found"))?; + ensure!(found == ["en-US", "fr"], "got {found:?}"); + Ok(()) +} + +#[test] +fn a_multiline_array_is_read() -> Result<()> { + let manifest = format!("{TABLE}locales = [\n \"en-US\",\n \"fr\",\n]\n\n[features]\n"); + let found = metadata_locales(&manifest) + .ok_or_else(|| anyhow!("expected the locales key to be found"))?; + ensure!(found == ["en-US", "fr"], "got {found:?}"); + Ok(()) +} + +/// The key must be matched as a whole assignment: a comment mentioning +/// locales, or a neighbouring key that merely ends in `locales`, must not be +/// read in its place. +#[rstest] +#[case("# locales = [\"wrong\"]\nlocales = [\"en-US\"]\n")] +#[case("extra_locales = [\"wrong\"]\nlocales = [\"en-US\"]\n")] +#[case("locales_note = \"see [wrong]\"\nlocales = [\"en-US\"]\n")] +fn decoys_do_not_displace_the_key(#[case] body: &str) -> Result<()> { + let manifest = format!("{TABLE}{body}"); + let found = metadata_locales(&manifest) + .ok_or_else(|| anyhow!("expected the locales key to be found"))?; + ensure!(found == ["en-US"], "got {found:?}"); + Ok(()) +} + +/// The table header must be matched only where it begins a line. A commented +/// or quoted mention of it earlier in the manifest previously captured the +/// search, so the parser returned the text above the real table and the audit +/// reported a valid manifest as missing its metadata. +#[rstest] +// A commented-out header before the real one. +#[case("# [package.metadata.ortho_config]\n# locales = [\"wrong\"]\n")] +// The header named inside a string value. +#[case("[package]\ndescription = \"see [package.metadata.ortho_config]\"\n")] +// Indented, so `begins_a_line` sees a preceding fragment that trims to empty +// and must still accept it as a real header. +#[case("[package]\nname = \"netsuke\"\n ")] +fn a_decoy_header_does_not_displace_the_table(#[case] preamble: &str) -> Result<()> { + let manifest = format!("{preamble}{TABLE}locales = [\"en-US\"]\n"); + let found = metadata_locales(&manifest) + .ok_or_else(|| anyhow!("expected the locales key to be found"))?; + ensure!(found == ["en-US"], "got {found:?}"); + Ok(()) +} + +/// A multiline string can contain a line that looks like the table header or +/// the key. Its content is not source, so it must not capture the search. +#[rstest] +// The header spelled inside a multiline basic string, at column zero. +#[case( + "[package]\ndescription = \"\"\"\n[package.metadata.ortho_config]\nlocales = [\"wrong\"]\n\"\"\"\n" +)] +// The same, in a multiline literal string. +#[case( + "[package]\ndescription = '''\n[package.metadata.ortho_config]\nlocales = [\"wrong\"]\n'''\n" +)] +fn a_multiline_string_decoy_does_not_displace_the_table(#[case] preamble: &str) -> Result<()> { + let manifest = format!("{preamble}{TABLE}locales = [\"en-US\"]\n"); + let found = metadata_locales(&manifest) + .ok_or_else(|| anyhow!("expected the real locales key to be found"))?; + ensure!(found == ["en-US"], "got {found:?}"); + Ok(()) +} + +/// A multiline string *inside* the table body can contain a line beginning +/// with `[`. That line is content, not the next table header, so it must not +/// end the table early and hide a `locales` key declared after it. +#[rstest] +// A header-shaped line inside a multiline basic string, before the key. +#[case("note = \"\"\"\n[not.a.header]\n\"\"\"\nlocales = [\"en-US\"]\n\n[features]\n")] +// The same, in a multiline literal string. +#[case("note = '''\n[not.a.header]\n'''\nlocales = [\"en-US\"]\n\n[features]\n")] +fn a_bracket_inside_a_table_string_does_not_end_the_table(#[case] body: &str) -> Result<()> { + let manifest = format!("{TABLE}{body}"); + let found = metadata_locales(&manifest) + .ok_or_else(|| anyhow!("expected the locales key inside the table to be found"))?; + ensure!(found == ["en-US"], "got {found:?}"); + Ok(()) +} + +/// A nested array value can open a line with `[` inside a multiline array. +/// +/// That line is a value, not the next table header, so the scan must continue +/// past it rather than truncating the table above the key that follows. +#[rstest] +// A nested string array before the key. +#[case("note = [\n[\"decoy\"],\n]\nlocales = [\"en-US\"]\n\n[features]\n")] +// The same with the nested value unterminated by a comma, as a final element. +#[case("note = [\n[\"decoy\"]\n]\nlocales = [\"en-US\"]\n\n[features]\n")] +fn a_nested_array_value_does_not_end_the_table(#[case] body: &str) -> Result<()> { + let manifest = format!("{TABLE}{body}"); + let found = metadata_locales(&manifest) + .ok_or_else(|| anyhow!("expected the locales key after the nested array to be found"))?; + ensure!(found == ["en-US"], "got {found:?}"); + Ok(()) +} + +#[rstest] +// No such table. +#[case("[package]\nname = \"netsuke\"\n")] +// The table, but no locales key. +#[case("[package.metadata.ortho_config]\nroot_type = \"x\"\n")] +// The key appears only after the table has ended. +#[case("[package.metadata.ortho_config]\nroot_type = \"x\"\n\n[other]\nlocales = [\"en-US\"]\n")] +// A quoted key names a table as legally as a bare one, so a quoted header +// ends the table too; reading past it would return the next table's keys. +#[case("[package.metadata.ortho_config]\n[\"release metadata\"]\nlocales = [\"en-US\"]\n")] +// The same, quoting one segment of a dotted header. +#[case("[package.metadata.ortho_config]\n[tool.\"release metadata\"]\nlocales = [\"en-US\"]\n")] +// A quoted header whose key contains an escaped quote: the escape is content, +// not the close, so this header too must end the table above its locales. +#[case("[package.metadata.ortho_config]\n[\"a\\\"b\"]\nlocales = [\"en-US\"]\n")] +// An unterminated array. +#[case("[package.metadata.ortho_config]\nlocales = [\"en-US\",\n")] +fn absent_or_unterminated_keys_yield_none(#[case] manifest: &str) -> Result<()> { + ensure!( + metadata_locales(manifest).is_none(), + "expected no locales, got {:?}", + metadata_locales(manifest) + ); + Ok(()) +} + +/// The repository manifest is the input this parser exists to read. +#[test] +fn the_repository_manifest_parses() -> Result<()> { + let found = metadata_locales(include_str!("../Cargo.toml")) + .ok_or_else(|| anyhow!("expected the repository manifest to declare locales"))?; + ensure!( + found.contains(&"en-US") && found.contains(&"zh-Hant"), + "expected the repository locales, got {found:?}" + ); + Ok(()) +} + +/// Fluent allows a blank line inside a multiline pattern; it does not end the +/// pattern. Clearing the current message there would drop the variables of +/// every continuation after it. +#[test] +fn a_blank_line_does_not_end_a_pattern() -> Result<()> { + let parsed = + parse("a.key = first { $one }\n continued { $two }\n\n after blank { $three }\n")?; + let found = variables_of(&parsed, "a.key")?; + ensure!( + found == ["one", "three", "two"], + "expected all three variables, got {found:?}" + ); + Ok(()) +} + +/// Only U+0020 indents a continuation. A tab-indented line is not one, so its +/// variables must not be attributed to the message above. +#[test] +fn a_tab_indented_line_is_not_a_continuation() -> Result<()> { + let parsed = parse("a.key = first { $one }\n\tb.key = tabbed { $two }\n")?; + let found = variables_of(&parsed, "a.key")?; + ensure!( + found == ["one"], + "expected only $one on a.key, got {found:?}" + ); + Ok(()) +} + +/// An indented continuation beginning with `#` is pattern text, not a comment. +/// +/// Fluent's comment syntax applies only to entry-starting lines, so a +/// continuation keeps its text whatever its first character. Reading it as a +/// comment dropped the variables it referenced — and dropping a variable makes +/// the audit *less* likely to complain, so it would have failed silently. +#[test] +fn an_indented_hash_line_continues_the_message() -> Result<()> { + let parsed = + parse("a.key = first { $one }\n #{ $two } still the pattern\nother = second\n")?; + let found = variables_of(&parsed, "a.key")?; + ensure!( + found == ["one", "two"], + "expected both variables, got {found:?}" + ); + // The continuation must not swallow the next entry: `other` starts a new + // message of its own, with nothing inherited from the pattern above. + ensure!( + variables_of(&parsed, "other")?.is_empty(), + "the next entry must start a fresh message with no variables" + ); + Ok(()) +} + +/// An unindented comment is still a comment. +#[test] +fn an_unindented_hash_line_is_a_comment() -> Result<()> { + let parsed = parse("a.key = first { $one }\n# { $ghost } a comment\nb.key = second\n")?; + let found = variables_of(&parsed, "a.key")?; + ensure!( + found == ["one"], + "a comment must contribute nothing, got {found:?}" + ); + Ok(()) +} + +/// Triple quotes inside an ordinary single-line string are content, not a +/// multiline delimiter. +/// +/// Counting delimiters without tracking single-line strings toggled the +/// multiline state on this text and mis-located the table. +#[rstest] +// The delimiter spelled inside a basic string. +#[case("[package]\ndescription = \"see \\\"\\\"\\\" here\"\n")] +// The same, inside a literal string, where backslashes do not escape. +#[case("[package]\ndescription = 'see \"\"\" here'\n")] +// A non-ASCII character before the table must not truncate the scan. +#[case("[package]\ndescription = \"a Ünicöde description — with dashes\"\n")] +fn string_content_does_not_toggle_the_multiline_state(#[case] preamble: &str) -> Result<()> { + let manifest = format!("{preamble}{TABLE}locales = [\"en-US\"]\n"); + let found = metadata_locales(&manifest) + .ok_or_else(|| anyhow!("expected the locales key to be found"))?; + ensure!(found == ["en-US"], "got {found:?}"); + Ok(()) +} diff --git a/tests/features/locale_resolution.feature b/tests/features/locale_resolution.feature index fee5d72f0..be3002a7c 100644 --- a/tests/features/locale_resolution.feature +++ b/tests/features/locale_resolution.feature @@ -43,7 +43,7 @@ Feature: Locale resolution Then no locale is resolved Scenario: Unsupported locale falls back to English messages - Given the configuration locale is "fr-FR" - And the system locale is "fr-FR" + Given the configuration locale is "is-IS" + And the system locale is "is-IS" When the runtime localiser is built Then the localised message contains "not found" diff --git a/tests/features/progress_output.feature b/tests/features/progress_output.feature index 9a90f0ad7..7b1755a60 100644 --- a/tests/features/progress_output.feature +++ b/tests/features/progress_output.feature @@ -91,7 +91,7 @@ Feature: Progress output And stderr should contain "Etapa 1/6" And stderr should contain "Etapa 6/6" And stderr should contain "Éxito:" - And stderr should contain "Generar completo." + And stderr should contain "Generar: operación finalizada." Scenario: Accessible mode prefixes stage labels with info marker Given a minimal Netsuke workspace diff --git a/tests/locale_catalogue_tests.rs b/tests/locale_catalogue_tests.rs new file mode 100644 index 000000000..3f5206971 --- /dev/null +++ b/tests/locale_catalogue_tests.rs @@ -0,0 +1,307 @@ +//! Content checks over every catalogue in the locale registry. +//! +//! These read the embedded catalogue text rather than rendering messages, so +//! they cover properties the build-time audit does not: the CLDR plural +//! categories each locale declares, the bidi marking right-to-left catalogues +//! rely on, and the guarantee that a translation is not simply a copy of the +//! English source. + +use std::collections::{BTreeMap, BTreeSet}; + +use anyhow::{Context, Result, ensure}; +use netsuke::locale_catalogues::{LocaleCatalogue, SOURCE_LOCALE, SUPPORTED_LOCALES, catalogue}; + +/// Message used to demonstrate plural handling in every catalogue. +const PLURAL_EXAMPLE: &str = "example.files_processed"; + +/// Locales whose copy may legitimately match the English source, because they +/// are English. +const ENGLISH_LOCALES: [&str; 2] = ["en-GB", SOURCE_LOCALE]; + +/// Embedded catalogue text for `tag`. +/// +/// # Errors +/// +/// Returns an error when the tag is absent from the locale registry. +fn catalogue_text(tag: &str) -> Result<&'static str> { + catalogue(tag) + .map(LocaleCatalogue::resource) + .with_context(|| format!("{tag} should be in the locale registry")) +} + +/// Extract the value of a single-line message from catalogue text. +fn message_value<'a>(text: &'a str, key: &str) -> Option<&'a str> { + text.lines() + .filter_map(|line| line.split_once('=')) + .find(|(id, _)| id.trim() == key) + .map(|(_, value)| value.trim()) +} + +/// Whether `value` opens a `select` expression. +fn opens_select(value: &str) -> bool { + value.ends_with("->") +} + +/// Collect the CLDR variants a `select` expression declares, and whether each +/// carries the `*` default marker. +/// +/// The scan runs in two passes over one iterator: find the line defining +/// `key`, then read variant lines until the closing brace. Only a `select` +/// opens a variant block — a plain message with the same key yields the empty +/// map rather than letting the scan run on and collect the categories of +/// whichever `select` came next. +/// +/// Variant lines look like `[one] …` or `*[other] …`. The marker is recorded +/// rather than trimmed away: Fluent falls back to the *starred* variant, so a +/// catalogue offering a plain `[other]` has no default at all and must not +/// pass for one. Numeric selectors such as `[0]` are exact matches rather than +/// CLDR categories, so they are skipped. +fn plural_variants(text: &str, key: &str) -> BTreeMap { + let mut lines = text.lines().map(str::trim); + let Some((_, value)) = + lines.find_map(|trimmed| trimmed.split_once('=').filter(|(id, _)| id.trim() == key)) + else { + return BTreeMap::new(); + }; + if !opens_select(value.trim()) { + return BTreeMap::new(); + } + lines + .take_while(|trimmed| *trimmed != "}") + .filter_map(|trimmed| { + let starred = trimmed.starts_with('*'); + let name = trimmed + .trim_start_matches('*') + .strip_prefix('[')? + .split(']') + .next()?; + (!name.chars().all(|ch| ch.is_ascii_digit())).then(|| (name.to_owned(), starred)) + }) + .collect() +} + +/// The CLDR categories a `select` expression declares, marker aside. +fn plural_categories(text: &str, key: &str) -> BTreeSet { + plural_variants(text, key).into_keys().collect() +} + +fn categories(names: &[&str]) -> BTreeSet { + names.iter().map(|name| (*name).to_owned()).collect() +} + +/// The CLDR cardinal plural categories each shipped locale must declare. +/// +/// Fluent selects variants through `intl_pluralrules` (7.0.2, per +/// `Cargo.lock`), so these are that crate's cardinal categories rather than +/// any newer CLDR release. Revisit the table when that dependency is bumped. +/// +/// The Romance locales carry `one`/`other` only. CLDR also defines `many` for +/// French, Spanish, Italian and Portuguese, but solely for large round numbers +/// in compact notation ("2 millions"); Netsuke counts files and errors as +/// plain integers, which never select it. +const PLURAL_CATEGORIES: &[(&str, &[&str])] = &[ + ("ar", &["zero", "one", "two", "few", "many", "other"]), + ("cs", &["one", "few", "many", "other"]), + ("cy", &["zero", "one", "two", "few", "many", "other"]), + ("da", &["one", "other"]), + ("de", &["one", "other"]), + ("el", &["one", "other"]), + ("en-GB", &["one", "other"]), + ("en-US", &["one", "other"]), + ("es-419", &["one", "other"]), + ("es-ES", &["one", "other"]), + ("fa", &["one", "other"]), + ("fi", &["one", "other"]), + ("fr", &["one", "other"]), + ("gd", &["one", "two", "few", "other"]), + // intl_pluralrules 7.0.2 implements CLDR 37, which gives Hebrew four + // cardinal categories: one, two, many, and other. + ("he", &["one", "two", "many", "other"]), + ("hi", &["one", "other"]), + // Hungarian keeps the noun singular after a numeral, so both variants read + // alike, but CLDR still defines `one` and a catalogue must offer it. + ("hu", &["one", "other"]), + ("id", &["other"]), + ("it", &["one", "other"]), + ("ja", &["other"]), + ("ko", &["other"]), + ("nb", &["one", "other"]), + ("nl", &["one", "other"]), + ("pl", &["one", "few", "many", "other"]), + ("pt-BR", &["one", "other"]), + ("pt-PT", &["one", "other"]), + ("ro", &["one", "few", "other"]), + ("ru", &["one", "few", "many", "other"]), + ("sv", &["one", "other"]), + ("th", &["other"]), + ("tr", &["one", "other"]), + ("uk", &["one", "few", "many", "other"]), + ("vi", &["other"]), + ("zh-Hans", &["other"]), + ("zh-Hant", &["other"]), +]; + +/// The table must name every shipped locale, or a catalogue could ship with +/// the wrong categories and never be checked. +#[test] +fn the_plural_table_covers_every_registry_locale() -> Result<()> { + let tabled: BTreeSet<&str> = PLURAL_CATEGORIES.iter().map(|(tag, _)| *tag).collect(); + for entry in SUPPORTED_LOCALES { + ensure!( + tabled.contains(entry.tag()), + "{} has no entry in PLURAL_CATEGORIES", + entry.tag() + ); + } + ensure!( + tabled.len() == SUPPORTED_LOCALES.len(), + "PLURAL_CATEGORIES has {} entries for {} locales", + tabled.len(), + SUPPORTED_LOCALES.len() + ); + Ok(()) +} + +/// Every locale must declare exactly the CLDR plural categories its language +/// uses; a translator who drops `few` from Polish silently loses a form. +#[test] +fn plural_examples_declare_the_language_categories() -> Result<()> { + for (tag, expected) in PLURAL_CATEGORIES { + let found = plural_categories(catalogue_text(tag)?, PLURAL_EXAMPLE); + ensure!( + found == categories(expected), + concat!( + "{tag} declares the CLDR plural categories {found:?} ", + "for {PLURAL_EXAMPLE}, expected {expected:?}" + ) + ); + } + Ok(()) +} + +/// Every catalogue's plural example must offer the `other` default, which +/// Fluent falls back to when no category matches. +/// +/// The variant has to be starred. Fluent resolves the fallback by the marker, +/// not by the name, so a plain `[other]` leaves the message with no default +/// and is a parse error rather than a working catalogue. +#[test] +fn every_plural_example_offers_the_default_variant() { + for entry in SUPPORTED_LOCALES { + let found = plural_variants(entry.resource(), PLURAL_EXAMPLE); + assert!( + found.get("other") == Some(&true), + "{} must declare the default `*[other]` variant, found {found:?}", + entry.tag() + ); + } +} + +/// A catalogue that merely copies the English source is not a translation. +#[test] +fn translations_are_not_copies_of_the_source() -> Result<()> { + let source = catalogue_text(SOURCE_LOCALE)?; + let sampled = ["cli.about", "manifest.parse", "status.state.pending"]; + let translated_locales = SUPPORTED_LOCALES + .iter() + .filter(|entry| !ENGLISH_LOCALES.contains(&entry.tag())); + for entry in translated_locales { + for key in sampled { + let translated = message_value(entry.resource(), key); + ensure!( + translated.is_some() && translated != message_value(source, key), + "{}: {key} still matches the English source", + entry.tag() + ); + } + } + Ok(()) +} + +/// Netsuke identifiers that users type must survive translation verbatim. +#[test] +fn catalogues_preserve_netsuke_identifiers() { + for entry in SUPPORTED_LOCALES { + let text = entry.resource(); + for token in ["cwd_mode", "with_suffix", "group_by", "ninja -t clean"] { + assert!( + text.contains(token), + "{} should keep the identifier `{token}` untranslated", + entry.tag() + ); + } + } +} + +/// A key that names a plain message must not borrow a later `select`'s +/// categories. +/// +/// This is the failure the two-pass scan exists to prevent: the requested key +/// is found, is not a `select`, and the scan stops there rather than running +/// on into `other.plural`. +#[test] +fn a_matching_non_select_message_yields_no_categories() -> Result<()> { + let catalogue = concat!( + "wanted.key = Just a message.\n", + "other.plural = { $count ->\n", + " [one] One.\n", + " *[other] Many.\n", + "}\n", + ); + let found = plural_categories(catalogue, "wanted.key"); + ensure!(found.is_empty(), "expected no categories, got {found:?}"); + Ok(()) +} + +/// A key absent from the catalogue yields nothing rather than the first +/// `select` it happens to meet. +#[test] +fn an_absent_key_yields_no_categories() -> Result<()> { + let catalogue = "other.plural = { $count ->\n [one] One.\n *[other] Many.\n}\n"; + let found = plural_categories(catalogue, "wanted.key"); + ensure!(found.is_empty(), "expected no categories, got {found:?}"); + Ok(()) +} + +/// Named selectors are collected; numeric ones are exact matches, not CLDR +/// categories, so they are skipped. The default `*` marker is not part of the +/// name. +#[test] +fn named_selectors_are_collected_and_numeric_ones_skipped() -> Result<()> { + let catalogue = concat!( + "wanted.key = { $count ->\n", + " [0] None at all.\n", + " [one] One.\n", + " [few] A few.\n", + " *[other] Many.\n", + "}\n", + ); + let found = plural_categories(catalogue, "wanted.key"); + ensure!( + found == categories(&["few", "one", "other"]), + "expected the named categories only, got {found:?}" + ); + Ok(()) +} + +/// The scan stops at the closing brace, so a `select` defined after the +/// requested one contributes nothing. +#[test] +fn the_scan_terminates_at_the_closing_brace() -> Result<()> { + let catalogue = concat!( + "wanted.key = { $count ->\n", + " [one] One.\n", + " *[other] Many.\n", + "}\n", + "later.plural = { $count ->\n", + " [two] Two.\n", + " *[other] Many.\n", + "}\n", + ); + let found = plural_categories(catalogue, "wanted.key"); + ensure!( + found == categories(&["one", "other"]), + "expected only the requested select's categories, got {found:?}" + ); + Ok(()) +} diff --git a/tests/locale_direction_tests.rs b/tests/locale_direction_tests.rs new file mode 100644 index 000000000..60b4bdd85 --- /dev/null +++ b/tests/locale_direction_tests.rs @@ -0,0 +1,192 @@ +//! Tests for the direction marking of right-to-left catalogues. +//! +//! Split from `locale_catalogue_tests.rs` to keep both files within the +//! repository's 400-line limit. That file checks what each catalogue declares; +//! this one checks how its rendered fragments read on a terminal. + +use anyhow::{Result, ensure}; +use rstest::rstest; + +use netsuke::locale_catalogues::{LocaleCatalogue, SUPPORTED_LOCALES}; + +/// The catalogue text for `tag`. +fn catalogue_text(tag: &str) -> Result<&'static str> { + SUPPORTED_LOCALES + .iter() + .find(|entry| entry.tag() == tag) + .map(LocaleCatalogue::resource) + .ok_or_else(|| anyhow::anyhow!("locale {tag} is not in the registry")) +} + +const fn is_rtl(ch: char) -> bool { + matches!(ch, '\u{0590}'..='\u{08FF}' | '\u{FB1D}'..='\u{FDFF}' | '\u{FE70}'..='\u{FEFF}') +} + +/// Right-to-left marker that pins a message's paragraph direction. +const RTL_MARK: char = '\u{200F}'; + +/// Messages that are deliberately direction-neutral. +/// +/// Each is either a bare technical token substituted into another message, or +/// an all-Latin diagnostic line. Pinning these to right-to-left would move a +/// Latin identifier to the wrong edge of the terminal, so they are exempt. +const DIRECTION_NEUTRAL: [&str; 5] = [ + // Clap's usage string, which names the binary and its Latin flags. + "cli.usage", + // Stream names, substituted into the command diagnostics. + "stdlib.command.output.stream.stdout", + "stdlib.command.output.stream.stderr", + // An all-Latin diagnostic tag followed by its detail. + "stdlib.which.args_error", + // A `{symbol} {label}` composition template for accessible output. + "semantic.prefix.rendered", +]; + +/// Whether `value` opens a `select` expression rather than carrying text. +/// +/// The selector line renders nothing; its variants carry the text, and they +/// are checked separately. +fn opens_select(value: &str) -> bool { + value.ends_with("->") +} + +/// The text a `select` variant line renders, if the line is one. +fn variant_text(trimmed: &str) -> Option<&str> { + trimmed + .trim_start_matches('*') + .strip_prefix('[')? + .split_once(']') + .map(|(_, rest)| rest.trim()) + .filter(|rest| !rest.is_empty()) +} + +/// The identifier a message line declares, with the text it renders. +/// +/// The text is `None` when the line opens a `select`, because the variants +/// carry the text instead, or when the value is empty. +fn message_text(trimmed: &str) -> Option<(&str, Option<&str>)> { + let (id, raw_value) = trimmed.split_once('=')?; + let value = raw_value.trim(); + let rendered = (!value.is_empty() && !opens_select(value)).then_some(value); + Some((id.trim(), rendered)) +} + +/// Every rendered fragment of a catalogue, as `(id, text)` pairs. +/// +/// A message's own value is one fragment; each variant of a `select` +/// expression is another, because whichever variant Fluent picks becomes the +/// whole rendered string and so decides the paragraph direction on its own. +/// How a catalogue line contributes to the rendered text. +enum Fragment<'line> { + /// Not rendered: a blank line or an entry-starting comment. + Skipped, + /// A `select` variant's text, belonging to the current message. + Variant(&'line str), + /// An indented continuation, belonging to the current message. + Continuation(&'line str), + /// A new message, with its own text when it has any. + Message(&'line str, Option<&'line str>), +} + +/// Classify one catalogue line. +/// +/// Indentation decides before the first character does: Fluent's comment +/// syntax applies only to a line that starts an entry, so an indented line is +/// pattern text even when it begins with `#`. +fn classify(line: &str) -> Fragment<'_> { + let trimmed = line.trim(); + if trimmed.is_empty() { + return Fragment::Skipped; + } + let indented = line.starts_with(' '); + if !indented && trimmed.starts_with('#') { + return Fragment::Skipped; + } + if let Some(rendered) = variant_text(trimmed) { + return Fragment::Variant(rendered); + } + if indented { + return Fragment::Continuation(trimmed); + } + message_text(trimmed).map_or(Fragment::Skipped, |(id, rendered)| { + Fragment::Message(id, rendered) + }) +} + +/// Every rendered fragment of a catalogue, as `(id, text)` pairs. +fn rendered_fragments(text: &str) -> Vec<(String, String)> { + let mut fragments = Vec::new(); + let mut current = String::new(); + for line in text.lines() { + match classify(line) { + Fragment::Skipped => {} + Fragment::Variant(rendered) | Fragment::Continuation(rendered) => { + fragments.push((current.clone(), rendered.to_owned())); + } + Fragment::Message(id, rendered) => { + id.clone_into(&mut current); + if let Some(body) = rendered { + fragments.push((current.clone(), body.to_owned())); + } + } + } + } + fragments +} + +/// A right-to-left message that opens with a Latin word, a bracket or a +/// placeable would otherwise take its paragraph direction from that token. +/// Prefixing the value with U+200F keeps the direction with the locale. +/// +/// Fluent wraps every interpolated value in bidi isolates, so a template built +/// only from placeables and punctuation — `[{ $state }] { $label }` — carries +/// no strong character at all and defaults to left-to-right. Those need the +/// mark just as much as a Latin-initial sentence does, so the check covers +/// every rendered fragment rather than only those with visible script. +#[rstest] +#[case("ar")] +#[case("fa")] +#[case("he")] +fn rtl_catalogues_pin_paragraph_direction(#[case] tag: &str) -> Result<()> { + for (id, value) in rendered_fragments(catalogue_text(tag)?) { + if DIRECTION_NEUTRAL.contains(&id.as_str()) { + continue; + } + let first = value.chars().next().unwrap_or(RTL_MARK); + ensure!( + first == RTL_MARK || is_rtl(first), + "{tag}: {id} renders text starting with {first:?}, which leaves the \ + paragraph direction to that character; prefix the value with U+200F" + ); + } + Ok(()) +} + +/// An indented continuation beginning with `#` is a rendered fragment. +/// +/// Classifying it as a comment dropped it from the fragment list, so +/// `rtl_catalogues_pin_paragraph_direction` would silently skip it rather than +/// check its direction marking — a gap that widens as a translator uses the +/// syntax. +#[test] +fn an_indented_hash_continuation_is_a_rendered_fragment() -> Result<()> { + let fragments = rendered_fragments("a.key = first\n #tagged continuation\n"); + ensure!( + fragments + .iter() + .any(|(id, text)| id == "a.key" && text.contains("#tagged continuation")), + "the indented continuation must be rendered, got {fragments:?}" + ); + Ok(()) +} + +/// An unindented comment is still skipped. +#[test] +fn an_unindented_comment_is_not_a_fragment() -> Result<()> { + let fragments = rendered_fragments("# a comment\na.key = first\n"); + ensure!( + !fragments.iter().any(|(_, text)| text.contains("a comment")), + "a comment must not be rendered, got {fragments:?}" + ); + Ok(()) +} diff --git a/tests/locale_registry_tests.rs b/tests/locale_registry_tests.rs new file mode 100644 index 000000000..a0a030f36 --- /dev/null +++ b/tests/locale_registry_tests.rs @@ -0,0 +1,268 @@ +//! Tests for the locale catalogue registry and its fallback policy. +//! +//! These cover the registry's structural invariants and the deliberate +//! fallback rules that keep region and script variants distinct. + +use std::collections::{BTreeMap, BTreeSet}; +use std::str::FromStr; + +use anyhow::{Context, Result, ensure}; +use ortho_config::LanguageIdentifier; +use proptest::prelude::*; +use rstest::rstest; + +use netsuke::locale_catalogues::{ + LocaleCatalogue, SOURCE_LOCALE, SUPPORTED_LOCALES, catalogue, resolve_catalogue, + source_catalogue, +}; + +/// The tag of the catalogue serving `requested`. +/// +/// Mirrors what `cli_localization::build_localizer` does with a requested +/// locale: parse it, resolve through the registry, and fall back to the source +/// catalogue when the tag will not parse. +fn resolve_catalogue_tag(requested: &str) -> &'static str { + LanguageIdentifier::from_str(requested) + .as_ref() + .map_or_else(|_| source_catalogue(), resolve_catalogue) + .tag() +} + +fn registry_tags() -> Vec<&'static str> { + SUPPORTED_LOCALES.iter().map(LocaleCatalogue::tag).collect() +} + +/// Every locale this release ships, written out rather than derived. +/// +/// The other tests in this file check the registry against itself, which keeps +/// them true no matter what the registry says. This list is the independent +/// statement of intent: adding or dropping a catalogue has to be a deliberate +/// edit here as well, so neither can happen by accident. +const EXPECTED_SHIPPED_TAGS: [&str; 35] = [ + "ar", "cs", "cy", "da", "de", "el", "en-GB", "en-US", "es-419", "es-ES", "fa", "fi", "fr", + "gd", "he", "hi", "hu", "id", "it", "ja", "ko", "nb", "nl", "pl", "pt-BR", "pt-PT", "ro", "ru", + "sv", "th", "tr", "uk", "vi", "zh-Hans", "zh-Hant", +]; + +#[test] +fn the_registry_ships_exactly_the_expected_locales() { + let shipped: BTreeSet<&str> = registry_tags().into_iter().collect(); + let expected: BTreeSet<&str> = EXPECTED_SHIPPED_TAGS.into_iter().collect(); + + let missing: Vec<&&str> = expected.difference(&shipped).collect(); + let unexpected: Vec<&&str> = shipped.difference(&expected).collect(); + assert!( + missing.is_empty() && unexpected.is_empty(), + "registry drifted from the expected locale set: missing {missing:?}, unexpected {unexpected:?}" + ); + assert_eq!( + expected.len(), + EXPECTED_SHIPPED_TAGS.len(), + "the expected list must not contain duplicates" + ); +} + +#[test] +fn registry_contains_the_source_locale() { + assert!( + catalogue(SOURCE_LOCALE).is_some(), + "the registry must contain the source locale {SOURCE_LOCALE}" + ); +} + +#[test] +fn registry_tags_are_unique_and_sorted() { + let tags = registry_tags(); + let unique: BTreeSet<&str> = tags.iter().copied().collect(); + assert_eq!(unique.len(), tags.len(), "registry tags must be unique"); + let mut sorted = tags.clone(); + sorted.sort_unstable(); + assert_eq!(tags, sorted, "registry tags must be declared in tag order"); +} + +#[test] +fn registry_tags_are_valid_language_identifiers() -> Result<()> { + for tag in registry_tags() { + let parsed = LanguageIdentifier::from_str(tag) + .with_context(|| format!("{tag} should be a valid language identifier"))?; + let canonical = parsed.to_string(); + ensure!( + canonical == tag, + "{tag} should already be in canonical form, canonicalized to {canonical}" + ); + } + Ok(()) +} + +#[test] +fn every_registry_catalogue_embeds_content() { + for entry in SUPPORTED_LOCALES { + assert!( + !entry.resource().trim().is_empty(), + "catalogue {} should not be empty", + entry.tag() + ); + } +} + +/// Every shipped tag resolves to its own catalogue rather than a relative. +#[test] +fn every_registry_tag_resolves_to_itself() -> Result<()> { + for tag in registry_tags() { + let resolved = resolve_catalogue_tag(tag); + ensure!( + resolved == tag, + "expected {tag} to resolve to itself, got {resolved}" + ); + } + Ok(()) +} + +#[rstest] +// Unknown languages fall back to the source locale. +#[case("tlh", SOURCE_LOCALE)] +#[case("xx-YY", SOURCE_LOCALE)] +// Unparseable input falls back to the source locale. +#[case("not a locale", SOURCE_LOCALE)] +#[case("", SOURCE_LOCALE)] +fn unsupported_locales_fall_back_to_the_source(#[case] requested: &str, #[case] expected: &str) { + assert_eq!(resolve_catalogue_tag(requested), expected); +} + +/// The registry's documented fallback rules, exercised tag by tag. +/// +/// The point of these cases is that region and script variants which differ in +/// substance stay apart: a Mexican request must not land on the Spain +/// catalogue, and a Taiwanese one must not land on the Simplified catalogue. +#[rstest] +// Spanish: Spain keeps its own copy, every other region shares es-419. +#[case("es", "es-ES")] +#[case("es-ES", "es-ES")] +#[case("es-419", "es-419")] +#[case("es-MX", "es-419")] +#[case("es-AR", "es-419")] +// Portuguese: Brazil and Portugal stay apart; other regions take European. +#[case("pt", "pt-PT")] +#[case("pt-BR", "pt-BR")] +#[case("pt-PT", "pt-PT")] +#[case("pt-AO", "pt-PT")] +// Chinese: script wins, and regions map to the script they conventionally use. +#[case("zh", "zh-Hans")] +#[case("zh-Hans", "zh-Hans")] +#[case("zh-Hant", "zh-Hant")] +#[case("zh-CN", "zh-Hans")] +#[case("zh-SG", "zh-Hans")] +#[case("zh-TW", "zh-Hant")] +#[case("zh-HK", "zh-Hant")] +#[case("zh-Hant-TW", "zh-Hant")] +#[case("zh-Hans-CN", "zh-Hans")] +// English: the bare tag keeps the source; other regions prefer British copy. +#[case("en", "en-US")] +#[case("en-US", "en-US")] +#[case("en-GB", "en-GB")] +#[case("en-AU", "en-GB")] +#[case("en-IE", "en-GB")] +// The Norwegian macrolanguage resolves to Bokmål. +#[case("no", "nb")] +#[case("nb-NO", "nb")] +// Languages shipping one catalogue serve all their regions from it. +#[case("fr-CA", "fr")] +#[case("de-AT", "de")] +#[case("ja-JP", "ja")] +#[case("pl-PL", "pl")] +fn fallback_rules_keep_regional_variants_distinct(#[case] requested: &str, #[case] expected: &str) { + assert_eq!( + resolve_catalogue_tag(requested), + expected, + "{requested} should resolve to {expected}" + ); +} + +/// Resolution must be total: whatever tag arrives, the caller gets a +/// catalogue that is actually in the registry, never a dangling or synthesised +/// one. Fixed cases cannot cover the tag space, so this is a property. +#[test] +fn resolution_always_lands_on_a_registry_catalogue() { + let tags: BTreeSet<&str> = registry_tags().into_iter().collect(); + proptest!(|(requested in "\\PC{0,24}")| { + let resolved = resolve_catalogue_tag(&requested); + prop_assert!( + tags.contains(resolved), + "{requested:?} resolved to {resolved:?}, which is not in the registry" + ); + }); +} + +/// A well-formed tag whose language ships a catalogue must reach that +/// language, never a different one. Generated from the registry so a new +/// locale is covered without editing the test. +#[test] +fn a_known_language_never_resolves_to_another_language() { + let languages: Vec = registry_tags() + .iter() + .map(|tag| tag.split('-').next().unwrap_or(tag).to_owned()) + .collect(); + let count = languages.len(); + proptest!(|(index in 0usize..1024, region in "[A-Z]{2}")| { + let Some(language) = languages.get(index.wrapping_rem(count)) else { + return Ok(()); + }; + let requested = format!("{language}-{region}"); + let Ok(parsed) = LanguageIdentifier::from_str(&requested) else { + return Ok(()); + }; + let resolved = resolve_catalogue(&parsed).tag(); + let resolved_language = resolved.split('-').next().unwrap_or(resolved); + prop_assert_eq!( + resolved_language, + language.as_str(), + "{} resolved to {}, changing language", + requested, + resolved + ); + }); +} + +/// Every language shipping more than one catalogue must have an explicit +/// fallback rule. +/// +/// Without one, `resolve_catalogue` reaches the sole-catalogue lookup, which +/// returns nothing for a language with two — so the request silently falls all +/// the way through to English. The rule is a judgement about which variants +/// are interchangeable and cannot be inferred, so nothing but a test can +/// require it. Derived from the registry rather than listed, so a new pair is +/// covered without editing this test. +#[test] +fn a_language_with_two_catalogues_has_a_fallback_rule() { + let mut per_language: BTreeMap<&str, Vec<&str>> = BTreeMap::new(); + for tag in registry_tags() { + let language = tag.split('-').next().unwrap_or(tag); + per_language.entry(language).or_default().push(tag); + } + + let missing: Vec<&str> = per_language + .iter() + .filter(|(_, tags)| tags.len() > 1) + .map(|(language, _)| *language) + .filter(|language| !has_fallback_rule(language)) + .collect(); + + assert!( + missing.is_empty(), + "these languages ship more than one catalogue but have no LANGUAGE_FALLBACKS \ + rule, so requests for them fall through to the source locale: {missing:?}" + ); +} + +/// Whether `language` resolves through an explicit fallback rule. +/// +/// `LANGUAGE_FALLBACKS` is private, so this probes the observable behaviour +/// instead: a language with a rule resolves a region it does not ship to one +/// of its own catalogues, where a language without one reaches the source. +fn has_fallback_rule(language: &str) -> bool { + let Ok(probe) = LanguageIdentifier::from_str(&format!("{language}-ZZ")) else { + return false; + }; + let resolved = resolve_catalogue(&probe).tag(); + resolved != SOURCE_LOCALE && resolved.starts_with(language) +} diff --git a/tests/localization_plural_tests.rs b/tests/localization_plural_tests.rs new file mode 100644 index 000000000..a023b9790 --- /dev/null +++ b/tests/localization_plural_tests.rs @@ -0,0 +1,335 @@ +//! Runtime plural-selection tests. +//! +//! Split from `localization_tests.rs` to keep both files within the +//! repository's 400-line limit. These cover what Fluent *selects* at run time; +//! `tests/locale_catalogue_tests.rs` covers what each catalogue *declares*, +//! which is a different question and deliberately kept separate. + +use std::collections::BTreeSet; + +use anyhow::{Context, Result, ensure}; +use fluent_bundle::FluentValue; +use netsuke::locale_catalogues::SUPPORTED_LOCALES; +use netsuke::localization::{self, keys}; +use ortho_config::LocalizationArgs; +use rstest::rstest; +use test_support::fluent::normalize_fluent_isolates; +use test_support::localizer::locale_localizer; + +/// The number of catalogues this release ships. +/// +/// `tests/locale_registry_tests.rs` pins the exact tag set; this count lets the +/// sweeps below assert they covered all of it rather than silently iterating a +/// shortened registry. +const EXPECTED_SHIPPED_LOCALE_COUNT: usize = 35; + +/// Counts chosen to select every CLDR cardinal category some shipped locale +/// uses. +/// +/// `zero` and `two` are Welsh and Arabic; `few` and `many` are Polish, Russian, +/// and Czech among others; `one` and `other` are near-universal. A locale +/// ignores the counts that its plural rules do not distinguish, so one list +/// serves them all. +const PLURAL_PROBE_COUNTS: [i64; 9] = [0, 1, 2, 3, 5, 6, 11, 21, 100]; + +/// The `(locale, count)` pairs whose idiomatic wording carries no numeral. +/// +/// Arabic and Hebrew name small quantities as words rather than digits — "one +/// file", and a dual form for two — and Arabic's `zero` variant reads "no files +/// were processed". Hindi overrides count zero with an exact `[0]` variant +/// reading "no files were processed", since its CLDR `one` category would +/// otherwise render "0 फ़ाइल". Omitting the numeral there is correct +/// translation, not a dropped interpolation, so these are listed rather than +/// excused by a weaker assertion: the sweep below requires the numeral +/// everywhere else, and requires its *absence* here, so a regression in either +/// direction fails. +const NUMERAL_OMITTED_BY_IDIOM: [(&str, i64); 6] = [ + ("ar", 0), + ("ar", 1), + ("ar", 2), + ("he", 1), + ("he", 2), + ("hi", 0), +]; + +/// Render `key` with a numeric `count`, as Fluent's plural selector requires. +/// +/// `LocalizedMessage::with_arg` stringifies its value, and a `FluentValue::String` +/// never matches a plural category — every locale would silently fall to +/// `*[other]`. Passing a `FluentValue::from(i64)` is what actually exercises +/// `intl_pluralrules`. +fn render_with_count(key: &str, count: i64) -> Option { + let mut args: LocalizationArgs<'_> = LocalizationArgs::new(); + args.insert("count", FluentValue::from(count)); + localization::localizer().lookup(key, Some(&args)) +} + +/// Plural selection must work at runtime, for every shipped locale. +/// +/// `tests/locale_catalogue_tests.rs` checks that each catalogue *declares* the +/// CLDR categories its language needs. That is a structural check on the FTL +/// text; it cannot tell whether Fluent actually selects those variants when +/// given a number. This renders `example.files_processed` through the live +/// localizer for a spread of counts, so a catalogue whose variants are declared +/// but unreachable fails here. +#[test] +fn plural_selection_renders_for_every_locale_and_count() -> Result<()> { + let mut covered = 0usize; + for entry in SUPPORTED_LOCALES { + let _guards = locale_localizer(entry.tag()); + for count in PLURAL_PROBE_COUNTS { + let rendered = + render_with_count(keys::EXAMPLE_FILES_PROCESSED, count).with_context(|| { + format!( + "locale {} returned no message for count {count}", + entry.tag() + ) + })?; + let message = normalize_fluent_isolates(&rendered); + ensure!( + !message.trim().is_empty(), + "locale {} rendered empty for count {count}", + entry.tag() + ); + ensure!( + !message.contains(keys::EXAMPLE_FILES_PROCESSED), + "locale {} fell back to the key identifier for count {count}: {message}", + entry.tag() + ); + let numeral_expected = !NUMERAL_OMITTED_BY_IDIOM.contains(&(entry.tag(), count)); + ensure!( + message.contains(&count.to_string()) == numeral_expected, + "locale {} count {count}: expected the numeral present={numeral_expected}, got {message}", + entry.tag() + ); + } + covered += 1; + } + ensure!( + covered == EXPECTED_SHIPPED_LOCALE_COUNT, + "plural sweep covered {covered} locales, expected {EXPECTED_SHIPPED_LOCALE_COUNT}" + ); + Ok(()) +} + +/// A numeric argument must actually reach the plural selector. +/// +/// This is the guard on the helper above: if `render_with_count` ever passed a +/// string, every locale would render its `*[other]` variant and the sweep would +/// still pass. A language whose `one` and `other` wordings differ proves the +/// selector ran. +#[test] +fn a_numeric_count_selects_a_different_variant_from_the_default() -> Result<()> { + let _guards = locale_localizer("en-US"); + + let singular = render_with_count(keys::EXAMPLE_FILES_PROCESSED, 1) + .context("en-US must render for count 1")?; + let plural = render_with_count(keys::EXAMPLE_FILES_PROCESSED, 2) + .context("en-US must render for count 2")?; + + ensure!( + singular != plural, + "count 1 and count 2 must select different variants, both gave {singular}" + ); + Ok(()) +} + +/// A stringified count must NOT select a category, which is why the helper +/// exists. Pinning this stops someone "simplifying" the helper back to +/// `with_arg` and silently disabling every plural assertion above. +#[test] +fn a_stringified_count_falls_through_to_the_default_variant() -> Result<()> { + let _guards = locale_localizer("en-US"); + + let mut args: LocalizationArgs<'_> = LocalizationArgs::new(); + args.insert("count", FluentValue::from("1")); + let as_string = localization::localizer() + .lookup(keys::EXAMPLE_FILES_PROCESSED, Some(&args)) + .context("en-US must render for a string count")?; + let as_number = render_with_count(keys::EXAMPLE_FILES_PROCESSED, 1) + .context("en-US must render for a numeric count")?; + + ensure!( + as_string != as_number, + "a string count must not select the `one` variant; both gave {as_string}" + ); + Ok(()) +} + +/// One declared variant of a `select` expression. +struct DeclaredVariant { + category: String, + /// The variant's literal text, still carrying `{ $count }`. + template: String, + /// Whether this is the `*` default, chosen when no category matches. + is_default: bool, +} + +/// The variants a catalogue's `key` declares. +/// +/// Exact numeric variants such as `[0]` are declared branches too: Fluent +/// selects an exact match ahead of any plural category, so leaving them out +/// would make the oracle below reject the very rendering the catalogue asks +/// for at that count. +fn declared_variants(resource: &str, key: &str) -> Vec { + let mut lines = resource.lines().map(str::trim); + let opened = lines + .find_map(|trimmed| trimmed.split_once('=').filter(|(id, _)| id.trim() == key)) + .is_some_and(|(_, value)| value.trim().ends_with("->")); + if !opened { + return Vec::new(); + } + lines + .take_while(|trimmed| *trimmed != "}") + .filter_map(|trimmed| { + let is_default = trimmed.starts_with('*'); + let (name, text) = trimmed + .trim_start_matches('*') + .strip_prefix('[')? + .split_once(']')?; + Some(DeclaredVariant { + category: name.to_owned(), + template: text.trim().to_owned(), + is_default, + }) + }) + .collect() +} + +/// Which declared categories could have produced `rendered` for `count`. +/// +/// More than one qualifies when a locale words two categories identically — +/// Hungarian and Turkish keep the noun singular after any numeral — so the +/// result is a set rather than a single answer. +fn matching_categories(variants: &[DeclaredVariant], rendered: &str, count: i64) -> Vec { + variants + .iter() + .filter(|variant| { + let expected = variant.template.replace("{ $count }", &count.to_string()); + normalize_fluent_isolates(&expected) == rendered + }) + .map(|variant| variant.category.clone()) + .collect() +} + +/// Every locale must select a declared branch, and at least one that is not +/// the default. +/// +/// The rendering sweep above cannot tell selection from fallback: a locale +/// that always resolved to `*[other]` would still render non-empty text +/// containing the numeral. This checks the rendered string against the +/// catalogue's own variant templates, so the branch Fluent actually chose is +/// identified rather than assumed. +#[test] +fn every_locale_selects_a_declared_plural_branch() -> Result<()> { + let mut covered = 0usize; + for entry in SUPPORTED_LOCALES { + let variants = declared_variants(entry.resource(), keys::EXAMPLE_FILES_PROCESSED); + ensure!( + !variants.is_empty(), + "locale {} declares no plural variants", + entry.tag() + ); + // Taken from this key's own variants: the first `*[` in the whole + // catalogue belongs to whichever select comes first, which need not be + // this one. + let default_category = variants + .iter() + .find(|variant| variant.is_default) + .map_or_else(|| "other".to_owned(), |variant| variant.category.clone()); + + let _guards = locale_localizer(entry.tag()); + let mut selected: BTreeSet = BTreeSet::new(); + for count in PLURAL_PROBE_COUNTS { + let rendered = render_with_count(keys::EXAMPLE_FILES_PROCESSED, count) + .with_context(|| format!("locale {} rendered nothing", entry.tag()))?; + let normalized = normalize_fluent_isolates(&rendered); + let matched = matching_categories(&variants, &normalized, count); + ensure!( + !matched.is_empty(), + "locale {} count {count} rendered {normalized:?}, which matches no declared variant", + entry.tag() + ); + selected.extend(matched); + } + + // A locale declaring only a default has nothing to select between. + if variants.len() > 1 { + ensure!( + selected + .iter() + .any(|category| *category != default_category), + "locale {} only ever selected its default `{default_category}` branch across {PLURAL_PROBE_COUNTS:?}", + entry.tag() + ); + } + covered += 1; + } + ensure!( + covered == EXPECTED_SHIPPED_LOCALE_COUNT, + "the oracle covered {covered} locales, expected {EXPECTED_SHIPPED_LOCALE_COUNT}" + ); + Ok(()) +} + +/// The example plural messages must resolve and interpolate their count. +/// +/// These pass the count through `LocalizedMessage::with_arg`, which stringifies +/// it, so they exercise the default variant only. That is deliberate: it is the +/// path most call sites take. `every_locale_selects_a_declared_plural_branch` +/// covers numeric selection. +#[rstest] +#[case("en-US", "Processed", "files.")] +#[case("es-ES", "procesaron", "archivos.")] +fn example_files_processed_message_resolves( + #[case] locale: &str, + #[case] expected_verb: &str, + #[case] expected_noun: &str, +) -> Result<()> { + let _guards = locale_localizer(locale); + + let message = localization::message(keys::EXAMPLE_FILES_PROCESSED) + .with_arg("count", 5) + .to_string(); + + ensure!( + message.contains(expected_verb), + "expected message for locale {locale} to contain {expected_verb:?}, got: {message}" + ); + ensure!( + message.contains(expected_noun), + "expected message for locale {locale} to contain {expected_noun:?}, got: {message}" + ); + // Verify the count variable was interpolated (appears somewhere in the message) + ensure!( + message.contains('5'), + "expected count variable to be interpolated, got: {message}" + ); + Ok(()) +} + +/// Verify that the example `errors_found` message resolves and interpolates correctly. +#[rstest] +#[case("en-US", "errors found.")] +#[case("es-ES", "encontraron")] +fn example_errors_found_message_resolves( + #[case] locale: &str, + #[case] expected_substring: &str, +) -> Result<()> { + let _guards = locale_localizer(locale); + + let message = localization::message(keys::EXAMPLE_ERRORS_FOUND) + .with_arg("count", 3) + .to_string(); + + ensure!( + message.contains(expected_substring), + "expected message for locale {locale} to contain {expected_substring:?}, got: {message}" + ); + // Verify the count variable was interpolated + ensure!( + message.contains('3'), + "expected count variable to be interpolated, got: {message}" + ); + Ok(()) +} diff --git a/tests/localization_tests.rs b/tests/localization_tests.rs index c97ed6fac..b7b84e06c 100644 --- a/tests/localization_tests.rs +++ b/tests/localization_tests.rs @@ -2,12 +2,15 @@ use std::sync::{Arc, MutexGuard}; -use anyhow::{Context, Result, ensure}; +use anyhow::{Context, Result, bail, ensure}; use rstest::rstest; use test_support::localizer_test_lock; use netsuke::cli_localization; +use netsuke::locale_catalogues::SUPPORTED_LOCALES; use netsuke::localization::{self, LocalizerGuard, keys}; +use ortho_config::{FluentLocalizer, LanguageIdentifier}; +use std::str::FromStr; use test_support::fluent::normalize_fluent_isolates; /// Guard pair holding both the test lock and the localizer override. @@ -55,84 +58,150 @@ fn which_message(command: &str) -> String { .to_string() } +/// The number of catalogues this release ships. +/// +/// `tests/locale_registry_tests.rs` pins the exact tag set; this count is what +/// lets the sweeps below assert they covered all of it rather than silently +/// iterating a shortened registry. +const EXPECTED_SHIPPED_LOCALE_COUNT: usize = 35; +/// Every catalogue must parse on its own, with no English underneath it. +/// +/// `build_localizer` layers the requested locale over the English source, so a +/// catalogue that fails to parse still renders — in English, with the same +/// arguments interpolated. That is indistinguishable from a working +/// translation at the rendering level, which is why the sweep below cannot +/// catch it. Building each resource directly with the defaults disabled can. +#[test] +fn every_catalogue_parses_without_the_english_fallback() -> Result<()> { + for entry in SUPPORTED_LOCALES { + let locale = LanguageIdentifier::from_str(entry.tag()) + .with_context(|| format!("locale {} is not a valid BCP 47 tag", entry.tag()))?; + let built = FluentLocalizer::builder(locale) + .with_consumer_resources([entry.resource()]) + .disable_defaults() + .try_build(); + if let Err(err) = built { + bail!( + "locale {} has a catalogue that does not parse: {err}", + entry.tag() + ); + } + } + Ok(()) +} +/// Every registered locale must render a message and interpolate its +/// arguments. This is a rendering sweep, not a parse check: see +/// `every_catalogue_parses_without_the_english_fallback` for the latter. +#[test] +fn every_locale_renders_and_interpolates() -> Result<()> { + let mut covered = 0usize; + for entry in SUPPORTED_LOCALES { + let _guards = localizer_guards(entry.tag())?; + let message = normalize_fluent_isolates(&which_message("cc")); + ensure!( + !message.trim().is_empty(), + "locale {} rendered an empty message", + entry.tag() + ); + ensure!( + message.contains("cc") && message.contains('0'), + "locale {} did not interpolate its arguments, got: {message}", + entry.tag() + ); + ensure!( + !message.contains(keys::STDLIB_WHICH_NOT_FOUND), + "locale {} rendered the key identifier instead of a message: {message}", + entry.tag() + ); + covered += 1; + } + ensure!( + covered == EXPECTED_SHIPPED_LOCALE_COUNT, + "the sweep covered {covered} locales, expected {EXPECTED_SHIPPED_LOCALE_COUNT}" + ); + Ok(()) +} + +/// Non-Latin catalogues must reach the terminal with their own script intact. #[rstest] -#[case("es-ES", "no encontrado")] -#[case("fr-FR", "not found")] -fn localisation_resolves_expected_message( +#[case("ja", '\u{3040}', '\u{30FF}')] +#[case("ko", '\u{AC00}', '\u{D7A3}')] +#[case("ru", '\u{0400}', '\u{04FF}')] +#[case("el", '\u{0370}', '\u{03FF}')] +#[case("th", '\u{0E00}', '\u{0E7F}')] +#[case("hi", '\u{0900}', '\u{097F}')] +#[case("zh-Hans", '\u{4E00}', '\u{9FFF}')] +fn non_latin_locales_render_their_own_script( #[case] locale: &str, - #[case] expected_substring: &str, + #[case] first: char, + #[case] last: char, ) -> Result<()> { let _guards = localizer_guards(locale)?; - let message = which_message("tool"); + let message = localization::message(keys::MANIFEST_PARSE).to_string(); ensure!( - message.contains(expected_substring), - "expected message to contain {expected_substring:?} for locale {locale}, got: {message}" + message.chars().any(|ch| (first..=last).contains(&ch)), + "expected {locale} to render characters in {first:?}..={last:?}, got: {message}" ); Ok(()) } -/// Verify that the example plural form messages are resolvable and interpolate -/// the count variable. Note: CLDR plural selection requires numeric `FluentValue` -/// types, but the current API passes strings, so only the default `[other]` -/// variant is selected. These tests verify the messages resolve and interpolate -/// correctly regardless of which variant is chosen. +/// Right-to-left locales must render right-to-left text, and a message that +/// opens with a Latin token must still carry the mark that pins the +/// paragraph's direction. #[rstest] -#[case("en-US", "Processed", "files.")] -#[case("es-ES", "procesaron", "archivos.")] -fn example_files_processed_message_resolves( +#[case("ar", '\u{0600}', '\u{06FF}')] +#[case("fa", '\u{0600}', '\u{06FF}')] +#[case("he", '\u{0590}', '\u{05FF}')] +fn rtl_locales_render_and_keep_direction_marks( #[case] locale: &str, - #[case] expected_verb: &str, - #[case] expected_noun: &str, + #[case] first: char, + #[case] last: char, ) -> Result<()> { let _guards = localizer_guards(locale)?; - let message = localization::message(keys::EXAMPLE_FILES_PROCESSED) - .with_arg("count", 5) - .to_string(); - - ensure!( - message.contains(expected_verb), - "expected message for locale {locale} to contain {expected_verb:?}, got: {message}" - ); + let message = localization::message(keys::MANIFEST_PARSE).to_string(); ensure!( - message.contains(expected_noun), - "expected message for locale {locale} to contain {expected_noun:?}, got: {message}" + message.chars().any(|ch| (first..=last).contains(&ch)), + "expected {locale} to render its own script, got: {message}" ); - // Verify the count variable was interpolated (appears somewhere in the message) + + let label = localization::message(keys::MANIFEST_YAML_LABEL).to_string(); ensure!( - message.contains('5'), - "expected count variable to be interpolated, got: {message}" + label.starts_with('\u{200F}'), + "expected {locale} to keep the right-to-left mark on a Latin-initial \ + message, got: {label:?}" ); Ok(()) } -/// Verify that the example `errors_found` message resolves and interpolates correctly. #[rstest] -#[case("en-US", "errors found.")] -#[case("es-ES", "encontraron")] -fn example_errors_found_message_resolves( +#[case("es-ES", "no encontrado")] +// Icelandic ships no catalogue, so the English source copy renders. +#[case("is-IS", "not found")] +// A tag that will not parse at all takes the same path. +#[case("not a locale", "not found")] +#[case("", "not found")] +// A region with no catalogue of its own reaches its language's copy. +#[case("de-AT", "nicht gefunden")] +// A Latin American region reaches es-419 rather than Spain's catalogue. +#[case("es-MX", "no se encontró")] +// Script and region variants stay apart at run time, not just in resolution. +#[case("zh-TW", "找不到")] +#[case("zh-CN", "未找到")] +fn localisation_resolves_expected_message( #[case] locale: &str, #[case] expected_substring: &str, ) -> Result<()> { let _guards = localizer_guards(locale)?; - let message = localization::message(keys::EXAMPLE_ERRORS_FOUND) - .with_arg("count", 3) - .to_string(); - + let message = which_message("tool"); ensure!( message.contains(expected_substring), - "expected message for locale {locale} to contain {expected_substring:?}, got: {message}" - ); - // Verify the count variable was interpolated - ensure!( - message.contains('3'), - "expected count variable to be interpolated, got: {message}" + "expected message to contain {expected_substring:?} for locale {locale}, got: {message}" ); Ok(()) } - #[rstest] fn variable_interpolation_works_correctly() -> Result<()> { let _guards = localizer_guards("en-US")?; diff --git a/tests/packaging_smoke_tests.rs b/tests/packaging_smoke_tests.rs index e945e106b..9e9b7216c 100644 --- a/tests/packaging_smoke_tests.rs +++ b/tests/packaging_smoke_tests.rs @@ -4,19 +4,32 @@ //! build-script sources remain in its manifest, where an omission would //! otherwise fail only during release. +use netsuke::locale_catalogues::SUPPORTED_LOCALES; use std::collections::BTreeSet; use std::env; use std::path::Path; use std::process::Command; -const REQUIRED_PACKAGED_FILES: [&str; 5] = [ - "build_l10n_audit.rs", +const REQUIRED_PACKAGED_FILES: [&str; 9] = [ + "build_l10n_audit/mod.rs", + "build_l10n_audit/compare.rs", + "build_l10n_audit/ftl.rs", + "build_l10n_audit/keys.rs", + "build_l10n_audit/scanner.rs", + "build_l10n_audit/byte_index.rs", + "build_l10n_audit/metadata.rs", "build.rs", "src/localization/keys.rs", - "locales/en-US/messages.ftl", - "locales/es-ES/messages.ftl", ]; +/// Every catalogue named by the locale registry must ship in the package; +/// omitting one would break the build-time audit for downstream builds. +fn required_catalogue_paths() -> Vec { + SUPPORTED_LOCALES + .iter() + .map(|entry| format!("locales/{}/messages.ftl", entry.tag())) + .collect() +} #[test] #[expect( clippy::disallowed_methods, @@ -61,6 +74,13 @@ fn packaged_manifest_retains_build_script_sources() { ); } + for required_path in required_catalogue_paths() { + assert!( + packaged_paths.contains(required_path.as_str()), + "packaged manifest should contain `{required_path}`" + ); + } + assert!( packaged_paths.iter().all(|path| Path::new(path) .components() diff --git a/tests/snapshots/build_l10n_audit_rules_tests__the_failure_message_reports_every_category.snap b/tests/snapshots/build_l10n_audit_rules_tests__the_failure_message_reports_every_category.snap new file mode 100644 index 000000000..6918ddd40 --- /dev/null +++ b/tests/snapshots/build_l10n_audit_rules_tests__the_failure_message_reports_every_category.snap @@ -0,0 +1,8 @@ +--- +source: tests/build_l10n_audit_rules_tests.rs +expression: message +--- +localization audit failed: +- missing in xx: a.key +- orphaned in xx: z.orphan +- variable mismatch in xx: b.key (expected $count, found $tally) diff --git a/tests/startup_diagnostics_tests.rs b/tests/startup_diagnostics_tests.rs new file mode 100644 index 000000000..89403b525 --- /dev/null +++ b/tests/startup_diagnostics_tests.rs @@ -0,0 +1,153 @@ +//! End-to-end tests for startup locale diagnostics. +//! +//! These run the built binary rather than calling into the library, because the +//! behaviour under test is a property of the whole startup sequence: the +//! subscriber is installed, the locale is resolved before the command line is +//! parsed, events are buffered, and the buffer is settled on whichever path the +//! run takes — including the ones that terminate inside `clap` and never return +//! to `run_with_args`. +//! +//! A unit test cannot cover that. An earlier one called `build_localizer` +//! directly and passed while the buffered warning was being dropped on every +//! early-exit path, because `clap::Error::exit` never returns and the settle +//! call sat after it. + +use anyhow::{Context, Result, ensure}; +use cap_std::{ambient_authority, fs::Dir}; +use rstest::rstest; +use tempfile::TempDir; +use test_support::netsuke::{NetsukeRun, run_netsuke_in_with_env}; + +/// A locale that ships no catalogue, and whose language ships none either, so +/// it resolves to the English source and reports a fallback. +const UNSUPPORTED_LOCALE: &str = "is-IS"; + +/// The message `build_localizer` emits when a request cannot be honoured. +const FALLBACK_WARNING: &str = "falling back to the source locale"; + +/// Run the binary with an explicitly empty environment, in an empty directory. +/// +/// `run_netsuke_in_with_env` clears the child's environment rather than +/// inheriting it, so what these tests observe depends only on the arguments +/// they pass. That matters here more than most: the behaviour under test is +/// how a *locale* is resolved, and `NETSUKE_LOCALE` in the developer's or CI +/// environment would otherwise silently take part. The temporary directory +/// does the same for the working tree, so `build` cannot find the +/// repository's own manifest. +fn run(args: &[&str]) -> Result { + let directory = TempDir::new().context("stage an empty working directory")?; + run_netsuke_in_with_env(directory.path(), args, &[]) +} + +fn stderr_of(run: &NetsukeRun) -> String { + run.stderr.clone() +} + +/// Human mode must report an unsupported startup locale, whichever way the run +/// ends. +/// +/// The three cases are the paths that leave `run_with_args` differently: a +/// usage error and `--help` both terminate inside `clap`, while a real command +/// runs on to the configuration merge. +#[rstest] +// Terminates inside clap, after printing a usage error. +#[case(&["--locale", UNSUPPORTED_LOCALE, "--not-a-flag"])] +// Terminates inside clap, after printing help. +#[case(&["--locale", UNSUPPORTED_LOCALE, "--help"])] +// Runs on past the configuration merge. +#[case(&["--locale", UNSUPPORTED_LOCALE, "build"])] +fn human_mode_reports_an_unsupported_startup_locale(#[case] args: &[&str]) -> Result<()> { + let output = run(args)?; + let stderr = stderr_of(&output); + ensure!( + stderr.contains(FALLBACK_WARNING), + "expected the fallback warning on stderr for {args:?}, got: {stderr}" + ); + ensure!( + stderr.contains(UNSUPPORTED_LOCALE), + "the warning must name the requested locale, got: {stderr}" + ); + Ok(()) +} + +/// A supported locale must not warn, or the warning would appear on every run +/// and stop carrying information. +#[test] +fn human_mode_stays_quiet_for_a_supported_locale() -> Result<()> { + let output = run(&["--locale", "fr", "--not-a-flag"])?; + let stderr = stderr_of(&output); + ensure!( + !stderr.contains(FALLBACK_WARNING), + "a shipped catalogue must not warn, got: {stderr}" + ); + Ok(()) +} + +/// JSON mode must leave stderr carrying exactly one diagnostic document. +/// +/// This is the requirement the buffering exists for: the fallback happens +/// before the effective mode is known, and the diagnostic is written to stderr, +/// so an eagerly emitted warning would corrupt the document a consumer parses. +#[test] +fn json_mode_emits_only_the_diagnostic_document() -> Result<()> { + let output = run(&["--locale", UNSUPPORTED_LOCALE, "--not-a-flag", "--json"])?; + let stderr = stderr_of(&output); + + ensure!( + !stderr.contains(FALLBACK_WARNING), + "JSON mode must not write the fallback warning to stderr, got: {stderr}" + ); + // Parsing the whole stream is the assertion: anything emitted beside the + // document — before or after — makes it fail. + let parsed: serde_json::Value = serde_json::from_str(&stderr) + .with_context(|| format!("stderr must be exactly one JSON document, got: {stderr}"))?; + ensure!( + parsed.get("schema_version").is_some(), + "expected a diagnostic document, got: {parsed}" + ); + Ok(()) +} + +/// JSON mode requested by configuration must settle the same way as `--json`. +/// +/// The startup hint is read from the arguments alone, so with only `--locale` +/// on the command line the mode is decided by the discovered project config. +/// The run proceeds past the configuration merge and fails on the missing +/// manifest, which is what leaves a diagnostic document to inspect; the +/// buffered fallback warning must have been discarded rather than written +/// beside it. +#[test] +fn config_file_json_emits_only_the_diagnostic_document() -> Result<()> { + let directory = TempDir::new().context("stage an empty working directory")?; + Dir::open_ambient_dir(directory.path(), ambient_authority()) + .context("open the staged directory")? + .write(".netsuke.toml", "json = true\n") + .context("write the project config")?; + + let output = run_netsuke_in_with_env(directory.path(), &["--locale", UNSUPPORTED_LOCALE], &[])?; + let stderr = stderr_of(&output); + + ensure!( + !stderr.contains(FALLBACK_WARNING), + "config-driven JSON mode must not write the fallback warning to stderr, got: {stderr}" + ); + let parsed: serde_json::Value = serde_json::from_str(&stderr) + .with_context(|| format!("stderr must be exactly one JSON document, got: {stderr}"))?; + ensure!( + parsed.get("schema_version").is_some(), + "expected a diagnostic document, got: {parsed}" + ); + Ok(()) +} + +/// The JSON help path writes nothing to stderr at all. +#[test] +fn json_mode_help_leaves_stderr_empty() -> Result<()> { + let output = run(&["--locale", UNSUPPORTED_LOCALE, "--help", "--json"])?; + let stderr = stderr_of(&output); + ensure!( + stderr.is_empty(), + "expected empty stderr on the JSON help path, got: {stderr}" + ); + Ok(()) +}