diff --git a/claude-notes/plans/2026-07-17-localization-i18n-design.md b/claude-notes/plans/2026-07-17-localization-i18n-design.md new file mode 100644 index 000000000..dfce22efc --- /dev/null +++ b/claude-notes/plans/2026-07-17-localization-i18n-design.md @@ -0,0 +1,384 @@ +# Localization / internationalization for Quarto 2 + +**Braid strand:** bd-llhlzd7p (epic) +**Status:** design draft — iterating with Carlos before execution +**Related strands:** bd-99ru (listing category sidebar labels), bd-fod3 (sidebar language selector), bd-apudk (citeproc locale silent-degrade) +**Follow-up strand:** bd-xzaiqpjq (Lua exposure of `quarto.language`; blocked by bd-2llqjsms + bd-a9g50za2 — no `pandoc.Meta` support in Lua filters yet) + +## Overview + +Bring Quarto 1's localization model to Q2. The guiding principle is unchanged +from Q1: **Quarto's own messages (CLI output, errors, logs) stay in English; +rendered documents localize.** Localization is driven by: + +1. **`lang`** — a document/project option holding a BCP 47 tag (`fr`, `pt-BR`, + `de-CH`). Flows to Pandoc-style `` and selects the term set. +2. **Shipped term files** — `_language.yml` (English defaults, ~111 keys) plus + `_language-.yml` per language (34 files in Q1), copied into this repo + and embedded in the binary. +3. **`language:`** — user-facing metadata key for overrides: an inline flat map + of terms, per-language subkeys (`language: { fr: { … } }`), or a path to a + custom YAML file. A `_language.yml` at the project root is picked up + automatically. + +We deliberately keep **key-level compatibility with Q1** (`crossref-fig-title`, +`callout-note-title`, `title-block-published`, `section-title-abstract`, …) so +existing documents, custom translation files, and the community's translation +contributions carry over unmodified. + +### Why Q2 gets to be simpler than Q1 + +Q1 delivers the resolved language table through four distinct channels (Lua +filter params, explicit copies into Pandoc metadata, direct TS reads into the +DOM, and the `$quarto.language.*$` defaults-file template namespace — see +`external-sources/quarto-cli/llm-docs/localization-architecture.md`). These +exist because Q1 straddles TS, Pandoc templates, and Lua with no shared memory. + +Q2 has a single render pipeline in one process. We can have **one resolved +term table** with exactly two consumer surfaces: + +- **Rust transforms/writers** read it through a typed accessor on the stage + context. +- **Templates** read it as the `$quarto.language.$` dotted namespace + (quarto-doctemplate already resolves dotted paths — zero engine changes). + +A third surface (the Lua filter API, mirroring Q1's `param("language")`) is +planned but deferred to a later phase. + +## Current state of Q2 (survey, 2026-07-17) + +No language machinery exists; all user-visible strings are hardcoded English. +High-leverage change points found in the survey: + +| Feature | Where | Today | +|---|---|---| +| Crossref display names | `crates/quarto-core/src/crossref/registry.rs:78-105` (`BUILTINS`) | English literals ("Figure", "Table", theorem family, callout-as-crossref) | +| Theorem sugar names | `crates/quarto-core/src/transforms/theorem.rs:62-67` | **Second copy** of the same display names | +| Crossref rendering | `crates/quarto-core/src/transforms/crossref_render.rs:695,730-731` | `format!("{kind}\u{a0}{n}")`, hardcoded `: ` title delimiter | +| Callout titles | `crates/quarto-core/src/transforms/callout_resolve.rs:250,272` | `capitalize(callout_type)` — mechanical, not a lookup | +| TOC title | `crates/quarto-core/src/transforms/toc_generate.rs:128` | `"Table of Contents"` literal | +| Title-block labels | `crates/quarto-core/src/template.rs:227,232,240` | "Author"/"Published"/"Abstract" hardcoded **in the template string** | +| `` | `crates/quarto-core/src/template.rs:81,146` | Works (generic metadata pass-through, no validation) | +| Revealjs | `crates/quarto-core/src/revealjs/assemble.rs:408` | **Bug:** hardcodes `` | +| LaTeX/Typst | — | No writers exist yet; babel/polyglossia is out of scope until they do | +| Code-fold label | — | Not implemented yet ("Show the code" doesn't exist in q2) | +| Search/listing UI | — | Not emitted from Rust yet (listing labels tracked in bd-99ru) | + +Metadata flows through `MetadataMergeStage` +(`crates/quarto-core/src/stage/stages/metadata_merge.rs`), producing fully +merged `doc.ast.meta` as `ConfigValue` trees. The template context is populated +by walking that tree (`crates/quarto-core/src/template.rs:590,627`), and dotted +namespaces like `$navigation.toc.title$` already work. + +## Design + +### D1. Term files ship in-repo, embedded + +- New directory `resources/language/` containing `_language.yml` + + `_language-.yml`, **copied** from + `external-sources/quarto-cli/src/resources/language/` (one-time copy per the + external-sources policy; never referenced in-place). Add a `README.md` noting + provenance + the upstream commit, and that updates are re-copies. +- Embedded via `include_dir!` in `quarto-core` (same pattern as + `resources.rs`'s knitr bundle), parsed on demand with `quarto-yaml`. +- Keys we don't consume yet (e.g. `listing-page-*`, `search-*`) still ship and + still resolve — they're inert until their features land, and user templates + can already reference them via `$quarto.language.*$`. + +### D2. Resolution semantics (Q1-compatible) + +A pure function in a new `quarto-core` module (working name +`crates/quarto-core/src/language.rs`): + +``` +resolve_language(lang_tag, embedded_defaults, project_root_file, + user_language_value) -> LanguageTerms +``` + +Merge order (lowest to highest precedence), matching Q1's `formatLanguage`: + +1. Embedded `_language.yml` (English base). +2. Embedded `_language-.yml`, walking BCP 47 subtags most + general first: `pt-BR` merges `_language-pt.yml` then `_language-pt-BR.yml`. +3. Project-root `_language.yml`, if present (auto-detected, same subtag walk + for sibling `_language-.yml` files). +4. User `language:` value: a **string** is a path to a YAML file (error if + missing); a **map** is used directly. In either case, top-level plain keys + apply unconditionally; per-language subkeys (`en:`, `fr:`, `fr-CA:`) apply + only when they match the subtag walk of `lang`, most general first. + +`lang` itself resolves as: CLI `--metadata lang=…` > document/project merged +metadata `lang` > default `"en"`. (Since resolution runs after +`MetadataMergeStage`, the standard six-level precedence handles most of this +for free.) + +Term keys are accepted leniently like Q1: known keys from the catalog, plus +`crossref-*-title` / `crossref-*-prefix` patterns for custom crossref types. +Unknown keys under `language:` produce a **warning diagnostic** (Q1 silently +validates against a schema; we can do better) but are still carried, so users +can reference custom terms from their own templates. + +Crossref-specific fallback, also Q1-compatible: `crossref-{type}-prefix` +defaults to `crossref-{type}-title` when omitted. + +### D3. One resolved table, two surfaces + +- **New pipeline stage** `LanguageResolveStage`, immediately after + `MetadataMergeStage` (before the DocumentProfile checkpoint, so profile + extraction and everything downstream can see it). +- The stage produces a `LanguageTerms` value (a thin newtype over + `BTreeMap` with accessor helpers like + `terms.get("callout-note-title")` and + `terms.crossref_title("fig")` / `terms.crossref_prefix("fig")` with the + prefix→title fallback built in). +- Storage: written into `doc.ast.meta` as a `ConfigValue` map under the + reserved key `quarto.language` (marked as system-injected). **Only the + `quarto.language` subtree is claimed** — we do not reserve the whole + top-level `quarto.*` namespace (decided 2026-07-17; that's more real estate + than this feature needs). Because the template context is built by walking + `meta`, this makes `$quarto.language.$` work with **no doctemplate + changes**. + Transforms access it through a `LanguageTerms::from_meta(&meta)` helper (or a + field on `StageContext` — decision point, see Open Questions). +- **DocumentProfile**: not added in v1. If a project-scoped feature later needs + terms without re-running the pipeline, we add a field + `profile_version` + bump per the profile contract. + +### D4. Consumers converted in v1 + +Each conversion replaces a hardcoded literal with a term lookup, keeping the +current English value as the built-in default (which is what `_language.yml` +contains anyway): + +1. **Callouts** — `callout_resolve.rs`: `callout-{note,tip,warning,important,caution}-title` + replaces `capitalize()` for the five known types (unknown/custom callout + types keep the capitalize fallback). +2. **Crossref + theorems** — seed `RefTypeRegistry::builtin()` display names + from `crossref--title` at registry construction, so localized `kind` + flows through `plain_data.kind` and both `crossref_render.rs` and + `theorem.rs` inherit it. This also **de-duplicates** the theorem-name table + (theorem.rs keeps only keyword→prefix mapping; display name comes from the + registry). References use `crossref--prefix` (with title fallback), + captions use `crossref--title` — matching Q1's split. + `environment-proof-title` (+ solution/remark) covers `render_proof`. +3. **TOC** — `toc_generate.rs`: default from `toc-title-document` + (`toc-title-website` reserved for the website "On this page" TOC when that + distinction lands). +4. **Title block** — replace the three hardcoded labels in + `FULL_HTML_TEMPLATE` with `$quarto.language.title-block-author-single$` + (single/plural chosen by author count — needs a small context flag), + `$…title-block-published$`, `$…section-title-abstract$`. +5. **Revealjs** — fix `assemble.rs:408` to emit the document's `lang` instead + of hardcoded `"en"`. +6. **``** — already works; add a regression test. + +Explicit **non-goals for v1** (each stays on its own strand / future phase): +CLI/log message localization (never a goal); LaTeX babel/polyglossia and Typst +`set text(lang:)` (no writers yet — but the design reserves nothing that would +block them: the writer just reads `lang` + terms); listing labels (bd-99ru +becomes a consumer of this table); search UI strings (client JS, needs a +JSON-blob channel like Q1's 2c — design when search lands); code-fold label +(feature not implemented); citeproc locales (separate CSL mechanism, bd-apudk); +`crossref.title-delim` and friends (Q1 crossref *options* are a separate +surface from language terms; tracked separately in crossref work). + +### D5. Lua filter API (deferred — follow-up strand bd-xzaiqpjq) + +Q1 exposes the table to Lua as `param("language")` plus per-key params. Q2 +cannot do the equivalent yet: **Lua filters have no `pandoc.Meta` support +today** — Meta↔ConfigValue marshaling design is bd-2llqjsms, and doc-level +filter invocation (the filters that would receive Meta) is bd-a9g50za2. + +This epic therefore only guarantees the *precondition*: `quarto.language` is +injected into `doc.ast.meta` before user filters run, so when Meta support +lands, the table is already in place. The exposure work itself — +verifying Meta visibility, choosing the blessed accessor, conformance tests +alongside the bd-grkrb9nj parity harnesses — is **bd-xzaiqpjq** +(discovered-from this epic, blocked by bd-2llqjsms and bd-a9g50za2) and is +*not* part of this epic's scope or closeout. + +### D6. Schema & docs + +- Add `lang` (string) and `language` (string-or-map) to the metadata schema + surface so `q2` validation/completions know them. +- New user-facing docs page `docs/authoring/language.qmd` mirroring Q1's, + rendered with `q2` itself (per repo policy). + +## Test plan (TDD — written first, per phase) + +Unit tests (phase 2, in `crates/quarto-core`, `tests/integration/language.rs` +registered in `main.rs` per the integration-test layout rule): + +- [ ] Merge order: base → `pt` → `pt-BR` subtag walk (assert a key overridden + at each level). +- [ ] `de-CH`, `fr-CA`, `sr-Latn`, `zh-TW` variant files resolve (real shipped + files, not fixtures). +- [ ] User inline flat map overrides shipped translation. +- [ ] Per-language subkeys: `language: { fr: {…}, en: {…} }` — only the + matching branch applies; `fr-CA` doc picks up `fr:` subkey. +- [ ] `language: custom.yml` file form; missing file is a hard error with a + source-located diagnostic. +- [ ] Project-root `_language.yml` auto-detection. +- [ ] `crossref-*-prefix` falls back to `crossref-*-title`. +- [ ] Unknown key under `language:` warns but is preserved and reachable from + a template. +- [ ] Every shipped `_language-*.yml` parses and only contains known keys / + known patterns (catalog integrity test). + +End-to-end render tests (phase 3-4, driving the real binary path per the +end-to-end verification policy; use languages where the term visibly differs +from English — `es` "Figura"/"Tabla", `de` "Abbildung", `fr` "Table des +matières"): + +- [ ] `lang: es` → callout renders "Nota", crossref renders "Figura 1", + caption "Figura 1: …", TOC title "Tabla de contenidos" (exact strings + from `_language-es.yml`). +- [ ] `lang: pt-BR` → a key that differs between `pt` and `pt-BR` renders the + `pt-BR` value. +- [ ] `language: { crossref-fig-title: "Figura" }` without `lang` → override + applies on English base. +- [ ] Title-block labels localized (`title-block-published`). +- [ ] `$quarto.language.$` resolves in a user-provided template + (including a custom/unknown key). +- [ ] `` emitted in HTML output; revealjs output no longer + hardcodes `lang="en"`. +- [ ] `lang` set at project level (`_quarto.yml`) localizes a document with no + front matter. + +## Phases / work items + +### Phase 0 — resources +- [x] Copy `_language*.yml` (35 files) + provenance README into + `resources/language/`; embed via `include_dir!`. +- [x] Catalog integrity test (parses, known keys). + +Phase 0 findings (2026-07-17): +- Upstream stray keys kept verbatim, allowlisted in the integrity test: + `_language-lt.yml` `search`, `_language-sv.yml` `callout-danger-title`. +- `_language-sr-Latn.yml` has **no** `_language-sr.yml` parent — the subtag + walk must tolerate missing intermediate layers (unit-tested in phase 2). +- quarto-yaml parses `key: ""` as Null (filed bd-gutochbq, upstream crate); + `parse_term_file` reads Scalar(Null) as the empty string. + +### Phase 1 — test skeletons +- [x] Write the unit-test suite above (failing / `#[ignore]`-staged as needed). + (`tests/integration/language_resolve.rs`, 18 tests, verified failing + against the missing API before implementation.) + +### Phase 2 — resolution core +- [x] `crates/quarto-core/src/language.rs`: `LanguageTerms`, subtag walk, + merge, file/inline/subkey handling, diagnostics. +- [x] Unit tests green. (21 language tests + full quarto-core suite, 2473 + passed.) + +Phase 1-2 notes: +- `resolve_language(lang, extra_layers)` has no diagnostics param: warnings + are emitted when layers are *built* (`structured_layer_from_config`, + `parse_language_file`), where key source locations are at hand. +- Unknown-key warning includes a note that the key remains reachable as + `$quarto.language.$` (tested: warning carries the key's location). +- Custom files are strict (non-string term value = hard error); + inline metadata is lenient (warn + skip the entry). + +### Phase 3 — pipeline integration +- [x] `LanguageResolveStage` after `MetadataMergeStage`; inject + `quarto.language` into `meta`; template namespace works. +- [x] Project-root auto-detection wired through project context. + +Phase 3 notes: +- Stage inserted in three builders: `build_html_pipeline_stages_with_options` + (covers native render + q2-preview), `build_wasm_html_pipeline`, and + `build_analysis_pipeline`. Deliberately **not** in `get_config`'s pipeline + (that surface shows user config, not derived state) nor the Pass-1 profile + pipeline in `orchestrator.rs` (profile doesn't carry terms in v1). +- `language: .yml` resolves against the document dir, then the project + root; missing file = source-located **error** diagnostic, render continues + on shipped terms. +- `LanguageTerms::from_meta(&meta)` is the transform-side accessor; + round-trip is tested. 10 pipeline tests in + `tests/integration/language_pipeline.rs`. + +### Phase 4 — consumers +- [x] Callout titles (TDD: es/fr render tests first). +- [x] Crossref/theorem registry seeding + theorem-table dedupe. +- [x] TOC title. +- [x] Title-block template variables (author single/plural flag). +- [x] Revealjs `lang` fix. +- [ ] Full-workspace verify (`cargo xtask verify` — WASM leg affected: + quarto-core changes). *(Deferred to session end, before push.)* + +Phase 4 notes: +- 7 smoke-all fixtures in `crates/quarto/tests/smoke-all/localization/` + (written first, all failing on exactly the localized strings, then green). +- Crossref: `RefTypeRegistry::localize_builtin_display_names` runs in + `PreEngineSugaringStage` *before* `extend_from_metadata`, so + `crossref.custom` display names win over locale defaults. Reference text + additionally prefers `crossref--prefix` (Q1 prefix→title fallback) + at render time; captions use the localized `kind`. Proof labels use + `environment-proof-title`. +- Theorem sugar now takes its display name from the registry (localized), + keeping `THEOREM_CLASSES`' English column only as the registry-less + test fallback — the duplicate display-name table is effectively gone. +- Title block: `labels.{author,published,abstract}` computed in Rust + (author single/plural by author count, Q1 `computeLabels` parity), + inserted before the metadata walk so a user `labels:` key wins. +- End-to-end record (policy §3): `cargo run --bin q2 -- render completo.qmd` + (es doc with toc/title-block/table+ref/theorem/proof/callout) — output + inspected: ``, "Tabla de contenidos", "Autor/a", + "Fecha de publicación", "Resumen", "Tabla 1: Una tabla", "Teorema 1 + (Pitágoras)", "Demostración.", "Advertencia". Revealjs scaffold verified + via `render_to_file` integration test (`lang="es"` / default `"en"`). +- Discovered (filed): bd-51k5yz4e — caption-form pipe tables + (`: Caption {#tbl-N}`) never get a numbered caption prefix (pre-existing, + language-independent; related bd-uwv2eec2). + +### Phase 5 — docs & closeout +- [x] Docs page: `docs/guides/authoring/document-language.qmd` (rendered + with q2; added to the site sidebar). +- [x] Schema entries for `lang`/`language`: **N/A for now** — q2 has no + document-metadata schema/completion surface yet (no analogue of Q1's + `definitions.yml`); when one lands, `lang` and `language` should be + added to it. +- [x] Changelog: no hub-client/ source changes in this epic, so the + hub-client changelog rule is not triggered. +- [x] Full `cargo xtask verify` + strand closeout. Run 2026-07-17: the + first run caught `include_dir` being native-only (fixed in 21cb8a04 — + terms now embed on wasm32 too). Second run: **every leg green** + (lints/clippy, fmt, Rust build, tree-sitter, 10110 Rust tests, + ts-packages build, WASM build, hub-client build + tests, + trace-viewer, shared packages) **except** the `quarto-hub-mcp` + "live:" suite — 20 timeouts against `wss://sync.automerge.org`, + which is down (same outage that has braid on the local sync server). + Environmental, unrelated to this epic; re-verify that leg when the + public sync server is back. +- (Lua visibility of `quarto.language` moved out of this epic → bd-xzaiqpjq, + blocked on Meta support: bd-2llqjsms, bd-a9g50za2.) + +Phase 5 notes: +- Visible side effect worth knowing: the default TOC title changed from + q2's old hardcoded "Table of Contents" to the catalog's + "Table of contents" (lowercase c) — this is Quarto 1's exact string, so + it's a parity gain, but it shows up in every default-English document. + +## Decisions (resolved with Carlos, 2026-07-17) + +1. **Namespace**: claim only `quarto.language.<...>` in metadata, not the + whole top-level `quarto.*`. Transport is meta injection; a `LanguageTerms` + accessor wraps reads so transforms never do stringly `ConfigValue` walks. +2. **Ship all 34 Q1 language files from day one.** +3. **Author single/plural**: compute the chosen label string in Rust (Q1 + parity with `computeLabels` in authors.lua) and expose the resolved string + to the template — no template-side count logic. +4. **Unknown `language:` keys**: emit a warning diagnostic, with q2's + source-location infrastructure pointing at the offending key (improvement + over Q1's silence). The key is still carried and template-reachable. +5. **TOC title precedence**: user `toc-title` metadata > language table + (`toc-title-document`) > built-in default. +6. **Callout key duplication**: match Q1 exactly — `callout-note-title` (plain + callouts) and `crossref-nte-title` (callout-as-crossref) stay independently + resolvable keys. Deprecating/merging redundant options is a possible future + pass, made safer by q2's source-mapped diagnostics. +7. **Lua exposure is out of scope for this epic** — no `pandoc.Meta` support + in q2 Lua filters yet. Follow-up: bd-xzaiqpjq (blocked by bd-2llqjsms, + bd-a9g50za2). This epic only ensures `quarto.language` is in `meta` before + filters run. diff --git a/crates/quarto-core/Cargo.toml b/crates/quarto-core/Cargo.toml index 4de14cda2..48a4c4026 100644 --- a/crates/quarto-core/Cargo.toml +++ b/crates/quarto-core/Cargo.toml @@ -61,6 +61,14 @@ quarto-highlight.workspace = true # follow-up bd-754f review may replace it with a Q2-native scheme. base64.workspace = true +# Compile-time embedding of `resources/language/` term files (bd-llhlzd7p). +# Deliberately NOT in the native-only section below: localization must work +# in the WASM preview pipeline too (LanguageResolveStage runs there), so the +# ~150KB of term YAML is embedded on both targets. The other in-tree +# `include_dir!` uses (knitr resources, builtin extensions) remain +# native-gated at their use sites. +include_dir = "0.7" + # Optional clap dep so types exposed to the CLI (e.g. `AttributionMode`) # can carry `ValueEnum` derives without forcing clap into the WASM tree # or other non-CLI consumers. The `quarto` crate enables this via @@ -73,7 +81,6 @@ clap = ["dep:clap"] # Native-only dependencies (for execution engines and resource extraction) [target.'cfg(not(target_arch = "wasm32"))'.dependencies] tempfile = "3" -include_dir = "0.7" which = "8" regex = "1.12" # `scraper` (CSS-selector HTML reader) for the L7 post-render upgrade diff --git a/crates/quarto-core/src/crossref/registry.rs b/crates/quarto-core/src/crossref/registry.rs index ab6fa765d..063dc1eaa 100644 --- a/crates/quarto-core/src/crossref/registry.rs +++ b/crates/quarto-core/src/crossref/registry.rs @@ -105,6 +105,27 @@ const BUILTINS: &[(&str, &str)] = &[ ]; impl RefTypeRegistry { + /// Localize built-in display names from the resolved language table + /// (bd-llhlzd7p): `kind` becomes the `crossref--title` term, + /// falling back to `crossref--prefix` for types that only define + /// a prefix (`sec`, `eq`). Only [`RefTypeSource::BuiltIn`] entries are + /// touched — `crossref.custom` display names are user config and win + /// over locale defaults, so call this *before* + /// [`Self::extend_from_metadata`]. + pub fn localize_builtin_display_names(&mut self, terms: &crate::language::LanguageTerms) { + for def in self.entries.values_mut() { + if def.source != RefTypeSource::BuiltIn { + continue; + } + let localized = terms + .crossref_title(&def.ref_type) + .or_else(|| terms.get(&format!("crossref-{}-prefix", def.ref_type))); + if let Some(name) = localized { + def.kind = name.to_string(); + } + } + } + /// Seed with built-ins only. Call [`Self::extend_from_metadata`] and /// [`Self::extend_from_promised`] next to complete the registry. pub fn builtin() -> Self { diff --git a/crates/quarto-core/src/language.rs b/crates/quarto-core/src/language.rs new file mode 100644 index 000000000..3e858784f --- /dev/null +++ b/crates/quarto-core/src/language.rs @@ -0,0 +1,524 @@ +//! Language term files and resolution (localization). +//! +//! Quarto's own messages stay in English; *rendered documents* localize. +//! The terms that appear in rendered output (callout titles, crossref +//! titles/prefixes, the TOC title, title-block labels, …) are defined in +//! per-language YAML files under `resources/language/` (embedded into the +//! binary at compile time) and can be overridden by users through the +//! `language:` metadata key. Key names are compatible with Quarto 1 +//! (`crossref-fig-title`, `callout-note-title`, `title-block-published`, …). +//! +//! Design: `claude-notes/plans/2026-07-17-localization-i18n-design.md` +//! (braid strand bd-llhlzd7p). + +use std::collections::BTreeMap; + +use include_dir::{Dir, include_dir}; +use pampa::utils::diagnostic_collector::DiagnosticCollector; +use quarto_config::InterpretationContext; +use quarto_pandoc_types::config_value::{ConfigMapEntry, ConfigValue, ConfigValueKind}; +use quarto_source_map::{By, SourceInfo}; +use yaml_rust2::Yaml; + +/// Embedded copies of `resources/language/_language*.yml` (see the README in +/// that directory for provenance and the update procedure). +static LANGUAGE_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/../../resources/language"); + +/// Name of the base (English-defaults) term file. This file is also the +/// authoritative catalog of known term keys. +pub const BASE_LANGUAGE_FILE: &str = "_language.yml"; + +/// Returns the contents of an embedded language file by name +/// (e.g. `_language-fr.yml`), or `None` if no such file ships. +pub fn embedded_language_file(name: &str) -> Option<&'static str> { + LANGUAGE_DIR.get_file(name).and_then(|f| f.contents_utf8()) +} + +/// Names of all embedded `_language*.yml` files, sorted. +pub fn embedded_language_file_names() -> Vec<&'static str> { + let mut names: Vec<&'static str> = LANGUAGE_DIR + .files() + .filter_map(|f| f.path().file_name().and_then(|n| n.to_str())) + .filter(|n| n.starts_with("_language") && n.ends_with(".yml")) + .collect(); + names.sort_unstable(); + names +} + +/// One resolved term: the display string plus where it was defined +/// (an embedded file, a project/user YAML file, or inline metadata). +#[derive(Debug, Clone, PartialEq)] +pub struct TermEntry { + /// The display string, e.g. `"Table des matières"`. + pub value: String, + /// Source location of the value for diagnostics. + pub source: SourceInfo, +} + +/// A flat `term-key → value` layer parsed from one term file. +/// +/// Layers stack during resolution: English base, then each BCP 47 subtag +/// variant, then project-root files, then user `language:` overrides. +#[derive(Debug, Clone, Default)] +pub struct TermLayer { + /// Term entries in key-sorted order (deterministic iteration). + pub terms: BTreeMap, +} + +/// Errors from parsing a term file. +#[derive(Debug, thiserror::Error)] +pub enum TermFileError { + #[error("{filename}: failed to parse YAML: {message}")] + Yaml { filename: String, message: String }, + #[error("{filename}: expected a top-level map of term keys to strings")] + NotAMap { filename: String }, + #[error("{filename}: value for key {key:?} is not a plain string")] + NonStringValue { filename: String, key: String }, +} + +/// Parses a term file's content into a flat [`TermLayer`]. +/// +/// Term files are read with [`InterpretationContext::ProjectConfig`] +/// semantics: bare strings stay literal strings (they are display text, not +/// markdown). Every value must be a plain scalar string; maps, arrays, and +/// non-string scalars are rejected. (Per-language *subkey maps*, which are +/// legal in user `language:` metadata, are handled at resolution time — a +/// term *file* is always flat.) +pub fn parse_term_file(content: &str, filename: &str) -> Result { + let yaml = quarto_yaml::parse_file(content, filename).map_err(|e| TermFileError::Yaml { + filename: filename.to_string(), + message: e.to_string(), + })?; + let mut diagnostics = DiagnosticCollector::new(); + let config = pampa::pandoc::yaml_to_config_value( + yaml, + InterpretationContext::ProjectConfig, + &mut diagnostics, + ); + term_layer_from_config(&config, filename) +} + +/// A structured term layer: plain term keys plus per-language sublayers. +/// +/// This is the shape of user-facing `language:` config — a map whose scalar +/// entries are unconditional term overrides and whose map entries are keyed +/// by a BCP 47 tag and apply only when the document's `lang` matches: +/// +/// ```yaml +/// language: +/// title-block-published: "Updated" # applies unconditionally +/// fr: +/// title-block-published: "Mis à jour" # applies when lang is fr / fr-* +/// ``` +#[derive(Debug, Clone, Default)] +pub struct StructuredTermLayer { + /// Unconditional term overrides. + pub terms: BTreeMap, + /// Per-language sublayers, keyed by BCP 47 tag (applied in subtag-walk + /// order, so `fr` applies before `fr-CA` when `lang: fr-CA`). + pub sublayers: BTreeMap, +} + +/// The resolved term table for one document render. +/// +/// Produced by [`resolve_language`]; consumed by AST transforms (via the +/// accessors here) and by templates (via the `quarto.language` metadata +/// subtree, see the `LanguageResolveStage`). +#[derive(Debug, Clone)] +pub struct LanguageTerms { + lang: String, + terms: BTreeMap, +} + +impl LanguageTerms { + /// The BCP 47 tag the table was resolved for (default `"en"`). + pub fn lang(&self) -> &str { + &self.lang + } + + /// The display string for a term key, if defined. + pub fn get(&self, key: &str) -> Option<&str> { + self.terms.get(key).map(|t| t.value.as_str()) + } + + /// The full entry (value + source) for a term key, if defined. + pub fn entry(&self, key: &str) -> Option<&TermEntry> { + self.terms.get(key) + } + + /// The crossref display title for a reference type (`fig`, `tbl`, …): + /// the value of `crossref--title`. + pub fn crossref_title(&self, ref_type: &str) -> Option<&str> { + self.get(&format!("crossref-{ref_type}-title")) + } + + /// The crossref reference prefix for a reference type: the value of + /// `crossref--prefix`, falling back to `crossref--title` + /// when no explicit prefix is defined (Quarto 1 semantics). + pub fn crossref_prefix(&self, ref_type: &str) -> Option<&str> { + self.get(&format!("crossref-{ref_type}-prefix")) + .or_else(|| self.crossref_title(ref_type)) + } + + /// Iterate over all resolved terms in key-sorted order. + pub fn iter(&self) -> impl Iterator { + self.terms.iter().map(|(k, v)| (k.as_str(), v)) + } + + /// Reads the resolved table back from merged document metadata. + /// + /// This is the accessor AST transforms use: the `LanguageResolveStage` + /// injects the table under `quarto.language` (and `lang` is ordinary + /// metadata), so any consumer holding `doc.ast.meta` can reconstruct + /// the table without extra plumbing. Returns `None` when the stage has + /// not run (no `quarto.language` in `meta`). + pub fn from_meta(meta: &ConfigValue) -> Option { + let lang = meta + .get("lang") + .and_then(|v| v.as_plain_text()) + .unwrap_or_else(|| "en".to_string()); + let table = meta.get("quarto")?.get("language")?; + let ConfigValueKind::Map(entries) = &table.value else { + return None; + }; + let mut terms = BTreeMap::new(); + for entry in entries { + let value = if matches!(entry.value.value, ConfigValueKind::Scalar(Yaml::Null)) { + String::new() + } else { + match entry.value.as_plain_text() { + Some(v) => v, + None => continue, + } + }; + terms.insert( + entry.key.clone(), + TermEntry { + value, + source: entry.value.source_info.clone(), + }, + ); + } + Some(LanguageTerms { lang, terms }) + } + + /// Builds the `ConfigValue` map the `LanguageResolveStage` injects at + /// `quarto.language`: every term as a literal string scalar, each entry + /// keeping the source location of the file/metadata that defined it. + pub fn to_config_value(&self) -> ConfigValue { + let entries = self + .terms + .iter() + .map(|(key, term)| ConfigMapEntry { + key: key.clone(), + key_source: term.source.clone(), + value: ConfigValue::new_string(term.value.clone(), term.source.clone()), + }) + .collect(); + ConfigValue::new_map(entries, SourceInfo::generated(By::programmatic_config())) + } +} + +/// The BCP 47 subtag prefix chain for a tag, most general first: +/// `"pt-BR"` → `["pt", "pt-BR"]`. (Exposed for the stage's sibling-file +/// probing; resolution itself uses it internally.) +pub fn language_subtag_prefixes(lang: &str) -> Vec { + subtag_prefixes(lang) +} + +/// The set of known term keys: the keys of the embedded base catalog +/// (`_language.yml`). +fn catalog_keys() -> &'static std::collections::BTreeSet { + static CATALOG: std::sync::OnceLock> = + std::sync::OnceLock::new(); + CATALOG.get_or_init(|| { + let content = embedded_language_file(BASE_LANGUAGE_FILE) + .expect("base language file is embedded at compile time"); + parse_term_file(content, BASE_LANGUAGE_FILE) + .expect("embedded base language file parses (integrity-tested)") + .terms + .into_keys() + .collect() + }) +} + +/// Whether `key` is a legal term key: in the base catalog, or matching the +/// `crossref--title` / `crossref--prefix` patterns (crossref +/// types are user-extensible, so those keys are accepted for any type). +pub fn is_known_term_key(key: &str) -> bool { + catalog_keys().contains(key) + || (key.starts_with("crossref-") && (key.ends_with("-title") || key.ends_with("-prefix"))) +} + +/// The BCP 47 subtag prefix chain for a tag, most general first: +/// `"pt-BR"` → `["pt", "pt-BR"]`. +fn subtag_prefixes(lang: &str) -> Vec { + let mut prefixes = Vec::new(); + let mut current = String::new(); + for subtag in lang.split('-') { + if !current.is_empty() { + current.push('-'); + } + current.push_str(subtag); + prefixes.push(current.clone()); + } + prefixes +} + +/// Resolves the term table for `lang`. +/// +/// Layer order (lowest to highest precedence): +/// +/// 1. the embedded base catalog (`_language.yml`, English defaults); +/// 2. the embedded `_language-.yml` files along the subtag walk of +/// `lang`, most general first (`pt` before `pt-BR`; missing intermediate +/// files are skipped — upstream ships `sr-Latn` with no `sr`); +/// 3. each layer in `extra_layers` in slice order (callers pass the +/// project-root `_language.yml` layer before the user `language:` +/// metadata layer). Within one layer, plain keys apply first, then +/// matching per-language sublayers in subtag-walk order — so a +/// lang-restricted subkey always beats a plain key from the same source. +/// +/// Unknown-key warnings are emitted when *layers are built* (see +/// [`structured_layer_from_config`]), not here: the resolved table keeps +/// unknown keys so custom templates can reference user-defined terms. +pub fn resolve_language(lang: &str, extra_layers: &[StructuredTermLayer]) -> LanguageTerms { + let mut terms: BTreeMap = BTreeMap::new(); + + // 1. Embedded base catalog. + if let Some(content) = embedded_language_file(BASE_LANGUAGE_FILE) + && let Ok(layer) = parse_term_file(content, BASE_LANGUAGE_FILE) + { + terms.extend(layer.terms); + } + + // 2. Embedded per-language files along the subtag walk. + for prefix in subtag_prefixes(lang) { + let filename = format!("_language-{prefix}.yml"); + if let Some(content) = embedded_language_file(&filename) { + // Embedded files are integrity-tested; a parse failure here is a + // build defect, not a user error. + let layer = parse_term_file(content, &filename) + .expect("embedded language file parses (integrity-tested)"); + terms.extend(layer.terms); + } + } + + // 3. Extra layers: plain keys, then lang-matching sublayers. + for layer in extra_layers { + for (key, entry) in &layer.terms { + terms.insert(key.clone(), entry.clone()); + } + for prefix in subtag_prefixes(lang) { + if let Some(sublayer) = layer.sublayers.get(&prefix) { + for (key, entry) in &sublayer.terms { + terms.insert(key.clone(), entry.clone()); + } + } + } + } + + LanguageTerms { + lang: lang.to_string(), + terms, + } +} + +/// Builds a [`StructuredTermLayer`] from user-facing `language:` config +/// (inline metadata or a custom YAML file parsed to a `ConfigValue`). +/// +/// - Scalar / inline values become unconditional term overrides. Values are +/// flattened to plain text (`as_plain_text`), so both literal strings +/// (project config) and markdown-interpreted strings (document metadata) +/// work. +/// - Map values become per-language sublayers keyed by the entry key +/// (a BCP 47 tag such as `en`, `fr`, `fr-CA`). +/// - Term keys that are neither in the catalog nor `crossref-*-title/-prefix` +/// shaped produce a **warning** diagnostic (pointing at the key), but are +/// kept: custom templates may reference user-defined terms. +/// - Values that cannot be read as text produce a warning and are skipped. +pub fn structured_layer_from_config( + config: &ConfigValue, + diagnostics: &mut DiagnosticCollector, +) -> StructuredTermLayer { + let mut layer = StructuredTermLayer::default(); + let ConfigValueKind::Map(entries) = &config.value else { + diagnostics.add( + quarto_error_reporting::DiagnosticMessageBuilder::warning( + "`language` must be a map of term keys to strings (or a path to a YAML file)", + ) + .with_location(config.source_info.clone()) + .build(), + ); + return layer; + }; + for entry in entries { + if let ConfigValueKind::Map(sub_entries) = &entry.value.value { + // Per-language sublayer: every value inside is a term. + let mut sublayer = TermLayer::default(); + for sub_entry in sub_entries { + if let Some(term) = + term_entry_from_config(&sub_entry.value, &sub_entry.key, diagnostics) + { + warn_if_unknown_key(&sub_entry.key, &sub_entry.key_source, diagnostics); + sublayer.terms.insert(sub_entry.key.clone(), term); + } + } + layer.sublayers.insert(entry.key.clone(), sublayer); + } else if let Some(term) = term_entry_from_config(&entry.value, &entry.key, diagnostics) { + warn_if_unknown_key(&entry.key, &entry.key_source, diagnostics); + layer.terms.insert(entry.key.clone(), term); + } + } + layer +} + +/// Reads one term value from config; warns and returns `None` when the value +/// is not usable as display text. +fn term_entry_from_config( + value: &ConfigValue, + key: &str, + diagnostics: &mut DiagnosticCollector, +) -> Option { + // quarto-yaml parses `key: ""` as Null (bd-gutochbq); a Null term is an + // empty display string either way. + let text = if matches!(value.value, ConfigValueKind::Scalar(Yaml::Null)) { + Some(String::new()) + } else { + value.as_plain_text() + }; + match text { + Some(text) => Some(TermEntry { + value: text, + source: value.source_info.clone(), + }), + None => { + diagnostics.add( + quarto_error_reporting::DiagnosticMessageBuilder::warning(format!( + "language term `{key}` must be a string; ignoring this entry" + )) + .with_location(value.source_info.clone()) + .build(), + ); + None + } + } +} + +/// Warns when a term key is neither in the catalog nor crossref-shaped. +fn warn_if_unknown_key(key: &str, key_source: &SourceInfo, diagnostics: &mut DiagnosticCollector) { + if !is_known_term_key(key) { + diagnostics.add( + quarto_error_reporting::DiagnosticMessageBuilder::warning(format!( + "unknown language term key `{key}`" + )) + .add_note( + "the key is kept and can be referenced from templates as \ + `$quarto.language.$`, but no built-in output uses it", + ) + .add_hint("Is the key name misspelled? See _language.yml for the known keys?") + .with_location(key_source.clone()) + .build(), + ); + } +} + +/// Parses user-facing language YAML content (a custom translation file, e.g. +/// `language: custom.yml`) into a [`StructuredTermLayer`]. +/// +/// Accepts both documented Quarto 1 forms: a flat term map, and a map of +/// per-language subkeys. Non-string term values are an error. +pub fn parse_language_file( + content: &str, + filename: &str, + diagnostics: &mut DiagnosticCollector, +) -> Result { + let yaml = quarto_yaml::parse_file(content, filename).map_err(|e| TermFileError::Yaml { + filename: filename.to_string(), + message: e.to_string(), + })?; + let mut parse_diags = DiagnosticCollector::new(); + let config = pampa::pandoc::yaml_to_config_value( + yaml, + InterpretationContext::ProjectConfig, + &mut parse_diags, + ); + let ConfigValueKind::Map(entries) = &config.value else { + return Err(TermFileError::NotAMap { + filename: filename.to_string(), + }); + }; + // Strict pass: unlike inline metadata (lenient, warning-based), a file + // with non-string term values is malformed. + for entry in entries { + match &entry.value.value { + ConfigValueKind::Map(sub_entries) => { + for sub_entry in sub_entries { + if !is_stringish(&sub_entry.value) { + return Err(TermFileError::NonStringValue { + filename: filename.to_string(), + key: format!("{}.{}", entry.key, sub_entry.key), + }); + } + } + } + v if is_stringish_kind(v) => {} + _ => { + return Err(TermFileError::NonStringValue { + filename: filename.to_string(), + key: entry.key.clone(), + }); + } + } + } + Ok(structured_layer_from_config(&config, diagnostics)) +} + +fn is_stringish(value: &ConfigValue) -> bool { + is_stringish_kind(&value.value) +} + +fn is_stringish_kind(kind: &ConfigValueKind) -> bool { + matches!( + kind, + ConfigValueKind::Scalar(Yaml::String(_) | Yaml::Null) | ConfigValueKind::PandocInlines(_) + ) +} + +/// Extracts a flat [`TermLayer`] from a parsed `ConfigValue` map. +fn term_layer_from_config( + config: &ConfigValue, + filename: &str, +) -> Result { + let ConfigValueKind::Map(entries) = &config.value else { + return Err(TermFileError::NotAMap { + filename: filename.to_string(), + }); + }; + let mut layer = TermLayer::default(); + for entry in entries { + // quarto-yaml parses `key: ""` as Null (bd-gutochbq); a Null term is + // an empty display string either way. + let value = if matches!(entry.value.value, ConfigValueKind::Scalar(Yaml::Null)) { + "" + } else { + match entry.value.as_str() { + Some(v) => v, + None => { + return Err(TermFileError::NonStringValue { + filename: filename.to_string(), + key: entry.key.clone(), + }); + } + } + }; + layer.terms.insert( + entry.key.clone(), + TermEntry { + value: value.to_string(), + source: entry.value.source_info.clone(), + }, + ); + } + Ok(layer) +} diff --git a/crates/quarto-core/src/lib.rs b/crates/quarto-core/src/lib.rs index 09b018c84..c055fbdc4 100644 --- a/crates/quarto-core/src/lib.rs +++ b/crates/quarto-core/src/lib.rs @@ -50,6 +50,7 @@ pub mod extension; pub mod filter_resolve; pub mod format; pub mod get_config; +pub mod language; pub mod metadata; pub mod output_sink; pub mod pipeline; diff --git a/crates/quarto-core/src/pipeline.rs b/crates/quarto-core/src/pipeline.rs index ff4808252..bf225cd74 100644 --- a/crates/quarto-core/src/pipeline.rs +++ b/crates/quarto-core/src/pipeline.rs @@ -61,9 +61,10 @@ use crate::stage::stages::ClipboardJsStage; use crate::stage::{ ApplyTemplateStage, AstTransformsStage, AttributionGenerateStage, CompileThemeCssStage, DocumentProfileStage, EngineExecutionStage, IncludeExpansionStage, IncludeResolveStage, - LinkResolutionStage, ListingItemInfoStage, LoadedSource, MathJsStage, MetadataMergeStage, - ParseDocumentStage, Pipeline, PipelineData, PipelineStage, PreEngineSugaringStage, - RenderHtmlBodyStage, ResourceReportStage, StageContext, UnwrapProfileStage, UserFiltersStage, + LanguageResolveStage, LinkResolutionStage, ListingItemInfoStage, LoadedSource, MathJsStage, + MetadataMergeStage, ParseDocumentStage, Pipeline, PipelineData, PipelineStage, + PreEngineSugaringStage, RenderHtmlBodyStage, ResourceReportStage, StageContext, + UnwrapProfileStage, UserFiltersStage, }; use crate::transform::TransformPipeline; use crate::transforms::{ @@ -278,6 +279,11 @@ pub fn build_html_pipeline_stages_with_options( let mut stages: Vec> = vec![ Box::new(ParseDocumentStage::new()), Box::new(MetadataMergeStage::new()), + // Resolve localized terms (`lang` + `language:` → `quarto.language` + // metadata) right after the merge so every downstream consumer — + // profile extraction, transforms, templates — sees the table + // (bd-llhlzd7p). + Box::new(LanguageResolveStage::new()), // Include-shortcode expansion runs before the profile // checkpoint so content spliced in via `{{< include … >}}` // (headings, code blocks, crossref targets) is visible to @@ -540,6 +546,9 @@ pub fn build_wasm_html_pipeline() -> Pipeline { Box::new(ParseDocumentStage::new()), // No EngineExecutionStage - code cells pass through as-is Box::new(MetadataMergeStage::new()), + // Localized-term resolution — same position/contract as the + // native pipeline (bd-llhlzd7p). + Box::new(LanguageResolveStage::new()), // Include expansion before the profile checkpoint — bd-xfwx. Box::new(IncludeExpansionStage::new()), // Resolve include-in-header / before-body / after-body @@ -690,6 +699,10 @@ pub fn build_analysis_pipeline() -> Pipeline { let stages: Vec> = vec![ Box::new(ParseDocumentStage::new()), Box::new(MetadataMergeStage::new()), + // Localized-term resolution — keeps analysis-path transforms in + // sync with the render pipelines once they consume terms + // (bd-llhlzd7p). + Box::new(LanguageResolveStage::new()), Box::new(IncludeExpansionStage::new()), Box::new(PreEngineSugaringStage::new()), Box::new(AstTransformsStage::with_pipeline( @@ -1925,59 +1938,63 @@ mod tests { #[test] fn test_build_html_pipeline_stages() { let stages = build_html_pipeline_stages(); - assert_eq!(stages.len(), 22); + assert_eq!(stages.len(), 23); assert_eq!(stages[0].name(), "parse-document"); assert_eq!(stages[1].name(), "metadata-merge"); + // Localized-term resolution (bd-llhlzd7p) directly follows the + // metadata merge so `quarto.language` is present for every + // downstream consumer, including the profile checkpoint. + assert_eq!(stages[2].name(), "language-resolve"); // Include expansion runs before the profile checkpoint (bd-xfwx) // so profiles reflect content spliced in via `{{< include ... >}}`. - assert_eq!(stages[2].name(), "include-expansion"); + assert_eq!(stages[3].name(), "include-expansion"); // include-resolve (bd-8kp3) sits between include-expansion and // the profile checkpoint so file-slot include dependencies are // recorded into `profile.includes` for cache invalidation. - assert_eq!(stages[3].name(), "include-resolve"); + assert_eq!(stages[4].name(), "include-resolve"); // Listings auto-fill (bd-izqh, L1) sits between include-resolve // and the profile checkpoint so `meta.listing-item.*` enrichment // is visible to `DocumentProfile.listing_item`. - assert_eq!(stages[4].name(), "listing-item-info"); + assert_eq!(stages[5].name(), "listing-item-info"); // Profile checkpoint (Phase 0 website epic, bd-f3jc). - assert_eq!(stages[5].name(), "document-profile"); + assert_eq!(stages[6].name(), "document-profile"); // Cross-doc body-link resolution (Phase 8 sub-phase 8.0d). - assert_eq!(stages[6].name(), "link-resolution"); - assert_eq!(stages[7].name(), "unwrap-profile"); - assert_eq!(stages[8].name(), "pre-engine-sugaring"); - assert_eq!(stages[9].name(), "engine-execution"); - assert_eq!(stages[10].name(), "compile-theme-css"); + assert_eq!(stages[7].name(), "link-resolution"); + assert_eq!(stages[8].name(), "unwrap-profile"); + assert_eq!(stages[9].name(), "pre-engine-sugaring"); + assert_eq!(stages[10].name(), "engine-execution"); + assert_eq!(stages[11].name(), "compile-theme-css"); // Bootstrap JS (bd-4eyf) sits immediately after CompileThemeCssStage // so the same theme predicate gates JS and CSS together. - assert_eq!(stages[11].name(), "bootstrap-js"); + assert_eq!(stages[12].name(), "bootstrap-js"); // ClipboardJsStage (Phase 2 of bd-1tl09) sits next to // bootstrap-js because both ship a Project-scoped JS payload // gated on minimal-HTML. clipboard-js additionally gates on // `code-copy != false`. - assert_eq!(stages[12].name(), "clipboard-js"); + assert_eq!(stages[13].name(), "clipboard-js"); // Attribution-generate runs before user filters so the // `quarto.attribution.*` Lua host binding sees a populated // sidecar (bd-0fd0). No-op when no provider is installed. - assert_eq!(stages[13].name(), "attribution-generate"); - assert_eq!(stages[14].name(), "user-filters-pre"); - assert_eq!(stages[15].name(), "ast-transforms"); - assert_eq!(stages[16].name(), "user-filters-post"); + assert_eq!(stages[14].name(), "attribution-generate"); + assert_eq!(stages[15].name(), "user-filters-pre"); + assert_eq!(stages[16].name(), "ast-transforms"); + assert_eq!(stages[17].name(), "user-filters-post"); // bd-o8pr Phase 3: finalize per-doc resource report. - assert_eq!(stages[17].name(), "resource-report"); - assert_eq!(stages[18].name(), "code-highlight"); + assert_eq!(stages[18].name(), "resource-report"); + assert_eq!(stages[19].name(), "code-highlight"); // Math-mode (bd-w5ov) walks the post-transform AST and // populates meta.math when math is present. Sits just before // render-html-body so any late-introduced math (sugar, user // filters, crossref `\tag{N}`) is visible. - assert_eq!(stages[19].name(), "math-js"); - assert_eq!(stages[20].name(), "render-html-body"); - assert_eq!(stages[21].name(), "apply-template"); + assert_eq!(stages[20].name(), "math-js"); + assert_eq!(stages[21].name(), "render-html-body"); + assert_eq!(stages[22].name(), "apply-template"); } #[test] fn test_build_html_pipeline() { let pipeline = build_html_pipeline(); - assert_eq!(pipeline.len(), 22); + assert_eq!(pipeline.len(), 23); } #[test] @@ -1994,7 +2011,9 @@ mod tests { // Includes `attribution-generate` (bd-0fd0) so hub-client // preview filters see the same `quarto.attribution.*` host // binding as the CLI. - assert_eq!(pipeline.len(), 19); + // Includes `language-resolve` (bd-llhlzd7p) so preview output + // localizes identically to `q2 render`. + assert_eq!(pipeline.len(), 20); let names = pipeline.stage_names(); // bd-4eyf: hub-client iframe reinit blows away stateful // Bootstrap components, so we deliberately omit `bootstrap-js` @@ -2025,8 +2044,9 @@ mod tests { use crate::stage::PipelineDataKind; let pipeline = build_analysis_pipeline(); - // Parse + MetadataMerge + IncludeExpansion + PreEngineSugaring + AstTransforms(analysis subset) - assert_eq!(pipeline.len(), 5); + // Parse + MetadataMerge + LanguageResolve + IncludeExpansion + + // PreEngineSugaring + AstTransforms(analysis subset) + assert_eq!(pipeline.len(), 6); assert_eq!(pipeline.expected_input(), PipelineDataKind::LoadedSource); assert_eq!(pipeline.expected_output(), PipelineDataKind::DocumentAst); } diff --git a/crates/quarto-core/src/revealjs/assemble.rs b/crates/quarto-core/src/revealjs/assemble.rs index ca073ca54..6e6ee9838 100644 --- a/crates/quarto-core/src/revealjs/assemble.rs +++ b/crates/quarto-core/src/revealjs/assemble.rs @@ -376,6 +376,15 @@ pub fn render_revealjs_document( .get("title") .and_then(|v| v.as_plain_text()) .unwrap_or_default(); + // Document language for ``; previously hardcoded "en" + // (bd-llhlzd7p). Falls back to "en" when unset, matching the html + // template's default-less behavior for reveal (the scaffold always + // emits the attribute). + let lang = meta + .get("lang") + .and_then(|v| v.as_plain_text()) + .unwrap_or_else(|| "en".to_string()); + let lang = attr_escape(&lang); let config = reveal_config_json(meta); // Deck-level footer/logo live OUTSIDE `.slides` (see `footer_logo_html`). @@ -405,7 +414,7 @@ pub fn render_revealjs_document( format!( r#" - + diff --git a/crates/quarto-core/src/stage/mod.rs b/crates/quarto-core/src/stage/mod.rs index 3610e6f83..443538314 100644 --- a/crates/quarto-core/src/stage/mod.rs +++ b/crates/quarto-core/src/stage/mod.rs @@ -112,9 +112,9 @@ pub use stages::CodeHighlightStage; pub use stages::{ ApplyTemplateStage, AstTransformsStage, AttributionGenerateStage, CaptureSpliceStage, CompileThemeCssStage, DocumentProfileStage, EngineExecutionStage, IncludeExpansionStage, - IncludeResolveStage, LinkResolutionStage, ListingItemInfoStage, MathJsStage, - MetadataMergeStage, ParseDocumentStage, PreEngineSugaringStage, RenderHtmlBodyStage, - ResourceReportStage, UnwrapProfileStage, UserFiltersStage, + IncludeResolveStage, LanguageResolveStage, LinkResolutionStage, ListingItemInfoStage, + MathJsStage, MetadataMergeStage, ParseDocumentStage, PreEngineSugaringStage, + RenderHtmlBodyStage, ResourceReportStage, UnwrapProfileStage, UserFiltersStage, }; // Re-export the trace_event macro diff --git a/crates/quarto-core/src/stage/stages/language_resolve.rs b/crates/quarto-core/src/stage/stages/language_resolve.rs new file mode 100644 index 000000000..b123e7485 --- /dev/null +++ b/crates/quarto-core/src/stage/stages/language_resolve.rs @@ -0,0 +1,273 @@ +/* + * stage/stages/language_resolve.rs + * Copyright (c) 2026 Posit, PBC + * + * Resolve the document's localization term table (bd-llhlzd7p). + */ + +//! Resolve the document's language term table and inject it into metadata. +//! +//! Runs immediately after [`MetadataMergeStage`](super::MetadataMergeStage), +//! so `lang` and `language:` are already merged across project, directory, +//! and document layers. The stage: +//! +//! 1. reads `lang` (BCP 47 tag, default `"en"`); +//! 2. stacks the term layers, lowest precedence first: the embedded +//! `_language*.yml` catalog (subtag walk), the project-root +//! `_language.yml` (+ `_language-.yml` siblings, projects only), +//! and the user `language:` value (inline map, or a path to a YAML file +//! resolved against the document directory, then the project root); +//! 3. injects the resolved table into `doc.ast.meta` at **`quarto.language`** +//! as literal string scalars. +//! +//! `quarto.language` is the single transport for localized terms: templates +//! read `$quarto.language.$` through the ordinary metadata→template +//! context walk, and AST transforms reconstruct the table with +//! [`LanguageTerms::from_meta`]. Only the `quarto.language` subtree is +//! reserved — the stage preserves any other user-set `quarto.*` keys. +//! +//! Design: `claude-notes/plans/2026-07-17-localization-i18n-design.md`. + +use async_trait::async_trait; +use pampa::utils::diagnostic_collector::DiagnosticCollector; +use quarto_error_reporting::DiagnosticMessageBuilder; +use quarto_pandoc_types::{ConfigMapEntry, ConfigValue, ConfigValueKind}; +use quarto_source_map::{By, SourceInfo}; + +use crate::language::{ + LanguageTerms, StructuredTermLayer, language_subtag_prefixes, parse_language_file, + parse_term_file, resolve_language, structured_layer_from_config, +}; +use crate::stage::{PipelineData, PipelineDataKind, PipelineError, PipelineStage, StageContext}; + +/// Resolve localized terms into `quarto.language` metadata. +pub struct LanguageResolveStage; + +impl LanguageResolveStage { + pub fn new() -> Self { + Self + } +} + +impl Default for LanguageResolveStage { + fn default() -> Self { + Self::new() + } +} + +#[async_trait(?Send)] +impl PipelineStage for LanguageResolveStage { + fn name(&self) -> &str { + "language-resolve" + } + + fn input_kind(&self) -> PipelineDataKind { + PipelineDataKind::DocumentAst + } + + fn output_kind(&self) -> PipelineDataKind { + PipelineDataKind::DocumentAst + } + + async fn run( + &self, + input: PipelineData, + ctx: &mut StageContext, + ) -> Result { + let PipelineData::DocumentAst(mut doc) = input else { + return Err(PipelineError::unexpected_input( + self.name(), + self.input_kind(), + input.kind(), + )); + }; + + let lang = doc + .ast + .meta + .get("lang") + .and_then(|v| v.as_plain_text()) + .unwrap_or_else(|| "en".to_string()); + + let mut collector = DiagnosticCollector::new(); + let mut layers: Vec = Vec::new(); + + // Project-root `_language.yml` auto-detection (projects only; Q1: + // "alongside your _quarto.yml"). + if !ctx.project.is_single_file + && let Some(layer) = project_root_layer(ctx, &lang, &mut collector) + { + layers.push(layer); + } + + // User `language:` value: an inline map, or a path to a YAML file. + if let Some(value) = doc.ast.meta.get("language") { + match &value.value { + ConfigValueKind::Map(_) => { + layers.push(structured_layer_from_config(value, &mut collector)); + } + _ => { + if let Some(path_str) = value.as_plain_text() + && let Some(layer) = load_language_file( + ctx, + &doc.path, + &path_str, + &value.source_info, + &mut collector, + ) + { + layers.push(layer); + } + } + } + } + + let terms = resolve_language(&lang, &layers); + inject_quarto_language(&mut doc.ast.meta, &terms); + + ctx.diagnostics.extend(collector.into_diagnostics()); + Ok(PipelineData::DocumentAst(doc)) + } +} + +/// Loads the project-root `_language.yml` (plus `_language-.yml` +/// siblings along the subtag walk of `lang`) as one structured layer. +fn project_root_layer( + ctx: &StageContext, + lang: &str, + collector: &mut DiagnosticCollector, +) -> Option { + let base_path = ctx.project.dir.join("_language.yml"); + if !ctx.runtime.is_file(&base_path).unwrap_or(false) { + return None; + } + let filename = base_path.to_string_lossy().to_string(); + let content = match ctx.runtime.file_read_string(&base_path) { + Ok(content) => content, + Err(e) => { + collector.add( + DiagnosticMessageBuilder::warning(format!("could not read {filename}: {e}")) + .build(), + ); + return None; + } + }; + let mut layer = match parse_language_file(&content, &filename, collector) { + Ok(layer) => layer, + Err(e) => { + collector.add(DiagnosticMessageBuilder::warning(e.to_string()).build()); + return None; + } + }; + // Sibling `_language-.yml` files act as per-language sublayers. + for prefix in language_subtag_prefixes(lang) { + let sibling = ctx.project.dir.join(format!("_language-{prefix}.yml")); + if !ctx.runtime.is_file(&sibling).unwrap_or(false) { + continue; + } + let sibling_name = sibling.to_string_lossy().to_string(); + match ctx + .runtime + .file_read_string(&sibling) + .map_err(|e| e.to_string()) + .and_then(|c| parse_term_file(&c, &sibling_name).map_err(|e| e.to_string())) + { + Ok(sublayer) => { + layer.sublayers.insert(prefix, sublayer); + } + Err(e) => { + collector.add( + DiagnosticMessageBuilder::warning(format!("could not use {sibling_name}: {e}")) + .build(), + ); + } + } + } + Some(layer) +} + +/// Loads a user-specified `language: .yml`, resolving the path against +/// the document directory first, then the project root. A missing or +/// malformed file is an **error** diagnostic (the config asked for a file +/// that cannot be honored); resolution continues with the shipped terms. +fn load_language_file( + ctx: &StageContext, + doc_path: &std::path::Path, + path_str: &str, + declared_at: &SourceInfo, + collector: &mut DiagnosticCollector, +) -> Option { + let doc_dir = doc_path + .parent() + .map_or_else(|| ctx.project.dir.clone(), |p| p.to_path_buf()); + let candidates = [doc_dir.join(path_str), ctx.project.dir.join(path_str)]; + let Some(path) = candidates + .iter() + .find(|p| ctx.runtime.is_file(p).unwrap_or(false)) + else { + collector.add( + DiagnosticMessageBuilder::error(format!( + "specified `language` file does not exist: {path_str}" + )) + .add_hint("Is the path relative to the document (or the project root)?") + .with_location(declared_at.clone()) + .build(), + ); + return None; + }; + let filename = path.to_string_lossy().to_string(); + let content = match ctx.runtime.file_read_string(path) { + Ok(content) => content, + Err(e) => { + collector.add( + DiagnosticMessageBuilder::error(format!("could not read {filename}: {e}")) + .with_location(declared_at.clone()) + .build(), + ); + return None; + } + }; + match parse_language_file(&content, &filename, collector) { + Ok(layer) => Some(layer), + Err(e) => { + collector.add( + DiagnosticMessageBuilder::error(e.to_string()) + .with_location(declared_at.clone()) + .build(), + ); + None + } + } +} + +/// Injects the resolved table at `meta.quarto.language`, preserving any +/// other user-set `quarto.*` subkeys. +fn inject_quarto_language(meta: &mut ConfigValue, terms: &LanguageTerms) { + let table = terms.to_config_value(); + let generated = || SourceInfo::generated(By::programmatic_config()); + + let ConfigValueKind::Map(ref mut entries) = meta.value else { + return; + }; + let language_entry = |table: ConfigValue| ConfigMapEntry { + key: "language".to_string(), + key_source: generated(), + value: table, + }; + if let Some(quarto) = entries.iter_mut().find(|e| e.key == "quarto") { + if let ConfigValueKind::Map(ref mut sub_entries) = quarto.value.value { + sub_entries.retain(|e| e.key != "language"); + sub_entries.push(language_entry(table)); + } else { + // A non-map `quarto:` value cannot host subkeys; replace it — + // the subtree is reserved for Quarto-injected state. + quarto.value = ConfigValue::new_map(vec![language_entry(table)], generated()); + } + } else { + entries.push(ConfigMapEntry { + key: "quarto".to_string(), + key_source: generated(), + value: ConfigValue::new_map(vec![language_entry(table)], generated()), + }); + } +} diff --git a/crates/quarto-core/src/stage/stages/mod.rs b/crates/quarto-core/src/stage/stages/mod.rs index bdfde6f34..a670641ec 100644 --- a/crates/quarto-core/src/stage/stages/mod.rs +++ b/crates/quarto-core/src/stage/stages/mod.rs @@ -48,6 +48,7 @@ mod document_profile; mod engine_execution; mod include_expansion; mod include_resolve; +mod language_resolve; mod link_resolution; mod listing_item_info; // Math-mode stage: injects a math-rendering JS engine (MathJax / KaTeX) @@ -82,6 +83,7 @@ pub use document_profile::DocumentProfileStage; pub use engine_execution::{ENGINE_CAPTURE_KIND, EngineExecutionStage}; pub use include_expansion::{IncludeExpansionStage, extract_include_path}; pub use include_resolve::IncludeResolveStage; +pub use language_resolve::LanguageResolveStage; pub use link_resolution::LinkResolutionStage; pub use listing_item_info::ListingItemInfoStage; pub use math_js::{DEFAULT_KATEX_URL_BASE, DEFAULT_MATHJAX_URL, MathEngine, MathJsStage}; diff --git a/crates/quarto-core/src/stage/stages/pre_engine_sugaring.rs b/crates/quarto-core/src/stage/stages/pre_engine_sugaring.rs index 3ab459414..97773a2fe 100644 --- a/crates/quarto-core/src/stage/stages/pre_engine_sugaring.rs +++ b/crates/quarto-core/src/stage/stages/pre_engine_sugaring.rs @@ -101,6 +101,13 @@ impl PipelineStage for PreEngineSugaringStage { .take() .unwrap_or_else(RefTypeRegistry::builtin); + // Localize built-in display names from the resolved term table + // (bd-llhlzd7p) before user config extends the registry, so + // `crossref.custom` names win over locale defaults. + if let Some(terms) = crate::language::LanguageTerms::from_meta(&doc.ast.meta) { + registry.localize_builtin_display_names(&terms); + } + // Extend the registry from `crossref.custom` and lift `crossref.ids` // into promised-id entries. Errors are non-fatal and become // diagnostics on the stage context. diff --git a/crates/quarto-core/src/transforms/authors_normalize.rs b/crates/quarto-core/src/transforms/authors_normalize.rs index 50bdb8aa4..f2f3c5426 100644 --- a/crates/quarto-core/src/transforms/authors_normalize.rs +++ b/crates/quarto-core/src/transforms/authors_normalize.rs @@ -526,29 +526,40 @@ fn funding_source_to_config_value(source: &FundingSource) -> ConfigValue { /// Compute the title-block heading labels. /// -/// Default English strings match Q1's `_language.yml` keys +/// Precedence per label (bd-llhlzd7p, Q1 `computeLabels` parity): +/// per-document `*-title` option > localized language term /// (`title-block-author-single`, `title-block-affiliation-plural`, -/// `title-block-published`, …); the per-document `*-title` options -/// override them. +/// `title-block-published`, `section-title-abstract`, …) > English +/// literal (the fallback when the `LanguageResolveStage` hasn't run, +/// e.g. in direct unit tests). `doi` and `description` have no term key +/// in the catalog — Q1 hardcodes them too. fn compute_labels( meta: &ConfigValue, author_count: usize, affiliation_count: usize, ) -> ConfigValue { let override_of = |key: &str| meta.get(key).and_then(|v| v.as_plain_text()); + let terms = crate::language::LanguageTerms::from_meta(meta); + let term = |key: &str, fallback: &str| -> String { + terms + .as_ref() + .and_then(|t| t.get(key)) + .unwrap_or(fallback) + .to_string() + }; let authors_label = override_of("author-title").unwrap_or_else(|| { if author_count > 1 { - "Authors".to_string() + term("title-block-author-plural", "Authors") } else { - "Author".to_string() + term("title-block-author-single", "Author") } }); let affiliations_label = override_of("affiliation-title").unwrap_or_else(|| { if affiliation_count > 1 { - "Affiliations".to_string() + term("title-block-affiliation-plural", "Affiliations") } else { - "Affiliation".to_string() + term("title-block-affiliation-single", "Affiliation") } }); let entries = vec![ @@ -560,14 +571,16 @@ fn compute_labels( map_entry( "published", ConfigValue::new_string( - override_of("published-title").unwrap_or_else(|| "Published".to_string()), + override_of("published-title") + .unwrap_or_else(|| term("title-block-published", "Published")), gen_si(), ), ), map_entry( "modified", ConfigValue::new_string( - override_of("modified-title").unwrap_or_else(|| "Modified".to_string()), + override_of("modified-title") + .unwrap_or_else(|| term("title-block-modified", "Modified")), gen_si(), ), ), @@ -581,7 +594,8 @@ fn compute_labels( map_entry( "abstract", ConfigValue::new_string( - override_of("abstract-title").unwrap_or_else(|| "Abstract".to_string()), + override_of("abstract-title") + .unwrap_or_else(|| term("section-title-abstract", "Abstract")), gen_si(), ), ), @@ -594,7 +608,7 @@ fn compute_labels( ), map_entry( "keywords", - ConfigValue::new_string("Keywords".to_string(), gen_si()), + ConfigValue::new_string(term("title-block-keywords", "Keywords"), gen_si()), ), ]; ConfigValue::new_map(entries, gen_si()) diff --git a/crates/quarto-core/src/transforms/callout_resolve.rs b/crates/quarto-core/src/transforms/callout_resolve.rs index aa55f876a..8441463a7 100644 --- a/crates/quarto-core/src/transforms/callout_resolve.rs +++ b/crates/quarto-core/src/transforms/callout_resolve.rs @@ -66,6 +66,7 @@ use quarto_source_map::{By, SourceInfo}; use serde_json::Value; use crate::Result; +use crate::language::LanguageTerms; use crate::render::RenderContext; use crate::transform::{AstTransform, TransformPhase}; @@ -103,64 +104,68 @@ impl AstTransform for CalloutResolveTransform { // ids on collapsible callouts. Starts at 1 to match TS Quarto's // `calloutidx` (`src/resources/filters/modules/callouts.lua`). let mut counter = 1u32; - resolve_blocks(&mut ast.blocks, &mut counter); + // Localized default titles (`callout--title`, bd-llhlzd7p); + // `None` when the LanguageResolveStage hasn't run (direct unit + // tests) — the capitalize() fallback applies then. + let terms = LanguageTerms::from_meta(&ast.meta); + resolve_blocks(&mut ast.blocks, &mut counter, terms.as_ref()); Ok(()) } } /// Resolve CustomNodes in a vector of blocks. -fn resolve_blocks(blocks: &mut Vec, counter: &mut u32) { +fn resolve_blocks(blocks: &mut Vec, counter: &mut u32, terms: Option<&LanguageTerms>) { for block in blocks.iter_mut() { - resolve_block(block, counter); + resolve_block(block, counter, terms); } } /// Resolve a single block, potentially converting CustomNode to Div. -fn resolve_block(block: &mut Block, counter: &mut u32) { +fn resolve_block(block: &mut Block, counter: &mut u32, terms: Option<&LanguageTerms>) { // First, recursively resolve any nested blocks match block { Block::BlockQuote(bq) => { - resolve_blocks(&mut bq.content, counter); + resolve_blocks(&mut bq.content, counter, terms); } Block::OrderedList(ol) => { for item in &mut ol.content { - resolve_blocks(item, counter); + resolve_blocks(item, counter, terms); } } Block::BulletList(bl) => { for item in &mut bl.content { - resolve_blocks(item, counter); + resolve_blocks(item, counter, terms); } } Block::DefinitionList(dl) => { for (_term, defs) in &mut dl.content { for def in defs { - resolve_blocks(def, counter); + resolve_blocks(def, counter, terms); } } } Block::Figure(fig) => { - resolve_blocks(&mut fig.content, counter); + resolve_blocks(&mut fig.content, counter, terms); } Block::Div(div) => { - resolve_blocks(&mut div.content, counter); + resolve_blocks(&mut div.content, counter, terms); } Block::Table(table) => { for body in &mut table.bodies { for row in &mut body.body { for cell in &mut row.cells { - resolve_blocks(&mut cell.content, counter); + resolve_blocks(&mut cell.content, counter, terms); } } } for row in &mut table.head.rows { for cell in &mut row.cells { - resolve_blocks(&mut cell.content, counter); + resolve_blocks(&mut cell.content, counter, terms); } } for row in &mut table.foot.rows { for cell in &mut row.cells { - resolve_blocks(&mut cell.content, counter); + resolve_blocks(&mut cell.content, counter, terms); } } } @@ -168,15 +173,15 @@ fn resolve_block(block: &mut Block, counter: &mut u32) { // First resolve any nested blocks in slots for (_name, slot) in &mut custom.slots { match slot { - Slot::Block(b) => resolve_block(b, counter), - Slot::Blocks(bs) => resolve_blocks(bs, counter), + Slot::Block(b) => resolve_block(b, counter, terms), + Slot::Blocks(bs) => resolve_blocks(bs, counter, terms), _ => {} } } // Then check if this is a Callout that should be resolved if custom.type_name == "Callout" { - let resolved_div = resolve_callout(custom, counter); + let resolved_div = resolve_callout(custom, counter, terms); *block = Block::Div(resolved_div); } } @@ -190,7 +195,11 @@ fn resolve_block(block: &mut Block, counter: &mut u32) { /// /// `counter` is bumped by 1 whenever a collapsible callout consumes /// it for the `callout-N-contents` id. -fn resolve_callout(custom: &mut CustomNode, counter: &mut u32) -> Div { +fn resolve_callout( + custom: &mut CustomNode, + counter: &mut u32, + terms: Option<&LanguageTerms>, +) -> Div { // Extract callout properties from plain_data. Appearance is // already normalized at CalloutTransform time (minimal → simple + // icon=false), so the resolver only sees `default` or `simple`. @@ -247,7 +256,7 @@ fn resolve_callout(custom: &mut CustomNode, counter: &mut u32) -> Div { Some(t) if !t.is_empty() => (Some(t), true), _ if appearance == "default" => ( Some(vec![Inline::Str(Str { - text: capitalize(&callout_type), + text: callout_display_name(&callout_type, terms), source_info: SourceInfo::generated(By::callout()), })]), false, @@ -269,7 +278,7 @@ fn resolve_callout(custom: &mut CustomNode, counter: &mut u32) -> Div { Inline::Span(quarto_pandoc_types::inline::Span { attr: make_attr(&["screen-reader-only"]), content: vec![Inline::Str(Str { - text: capitalize(&callout_type), + text: callout_display_name(&callout_type, terms), source_info: SourceInfo::generated(By::callout()), })], source_info: SourceInfo::generated(By::callout()), @@ -569,6 +578,16 @@ fn extract_bool(value: &Value, key: &str) -> Option { value.get(key).and_then(|v| v.as_bool()) } +/// The display name for a callout type: the localized +/// `callout--title` term when available (bd-llhlzd7p), else the +/// capitalized type keyword (which is also how unknown/custom callout +/// types are titled). +fn callout_display_name(callout_type: &str, terms: Option<&LanguageTerms>) -> String { + terms + .and_then(|t| t.get(&format!("callout-{callout_type}-title"))) + .map_or_else(|| capitalize(callout_type), |s| s.to_string()) +} + /// Capitalize the first letter of a string. fn capitalize(s: &str) -> String { let mut chars = s.chars(); @@ -739,7 +758,7 @@ mod tests { custom.plain_data = json!({"type": "note"}); // No title slot - should use default - let resolved = resolve_callout(&mut custom, &mut 1); + let resolved = resolve_callout(&mut custom, &mut 1, None); // Find the title container and check it has "Note" let header = &resolved.content[0]; @@ -766,7 +785,7 @@ mod tests { let mut custom = CustomNode::new("Callout", empty_attr(), dummy_source_info()); custom.plain_data = json!({"type": "warning", "icon": false}); - let resolved = resolve_callout(&mut custom, &mut 1); + let resolved = resolve_callout(&mut custom, &mut 1, None); // Q1-parity: header always contains an icon container; the // `no-icon` marker lives on the outer div + the inner ``. @@ -985,7 +1004,7 @@ mod tests { Some(vec![str_inline("Watch Out")]), vec![para("Body")], ); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); let classes = outer_classes(&resolved); assert_has_class(&classes, "callout"); assert_has_class(&classes, "callout-style-default"); @@ -1000,7 +1019,7 @@ mod tests { #[tokio::test] async fn test_canonical_default_no_title_injects_default() { let mut node = callout_node("tip", Some("default"), None, None, None, vec![para("Body")]); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); let classes = outer_classes(&resolved); assert_has_class(&classes, "callout-style-default"); assert_has_class(&classes, "callout-titled"); @@ -1014,7 +1033,7 @@ mod tests { #[tokio::test] async fn test_canonical_simple_no_title_stays_untitled() { let mut node = callout_node("note", Some("simple"), None, None, None, vec![para("Body")]); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); let classes = outer_classes(&resolved); assert_has_class(&classes, "callout-style-simple"); assert_no_class(&classes, "callout-titled"); @@ -1063,7 +1082,7 @@ mod tests { Some(vec![str_inline("Please Read")]), vec![para("Body")], ); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); let classes = outer_classes(&resolved); assert_has_class(&classes, "callout-style-simple"); assert_has_class(&classes, "callout-titled"); @@ -1084,7 +1103,7 @@ mod tests { None, vec![para("Body")], ); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); let classes = outer_classes(&resolved); assert_has_class(&classes, "callout-style-simple"); assert_no_class(&classes, "callout-style-minimal"); @@ -1117,7 +1136,7 @@ mod tests { Some(vec![str_inline("Heads Up")]), vec![para("Body")], ); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); assert_has_class(&outer_classes(&resolved), "no-icon"); assert!( contains_class_anywhere(&resolved, "callout-icon-container"), @@ -1141,7 +1160,7 @@ mod tests { Some(vec![str_inline("Heads Up")]), vec![para("Body")], ); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); let raw_icon_html = collect_raw_html(&resolved); assert!( raw_icon_html.contains("callout-icon no-icon"), @@ -1162,7 +1181,7 @@ mod tests { Some(vec![str_inline("Heads Up")]), vec![para("Body")], ); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); let raw_icon_html = collect_raw_html(&resolved); assert!( raw_icon_html.contains("callout-icon"), @@ -1209,7 +1228,7 @@ mod tests { Some(vec![str_inline("Heads Up")]), vec![], ); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); assert_has_class(&outer_classes(&resolved), "callout-empty-content"); } @@ -1223,7 +1242,7 @@ mod tests { Some(vec![str_inline("Title")]), vec![para("Body")], ); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); let header = match &resolved.content[0] { Block::Div(d) => d, other => panic!("expected header Div, got {:?}", other), @@ -1244,7 +1263,7 @@ mod tests { Some(vec![str_inline("T")]), vec![para("Body")], ); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); // Expected structure: outer > [header, collapse-wrapper]; // collapse-wrapper > body. assert_eq!( @@ -1304,7 +1323,7 @@ mod tests { Some(vec![str_inline("T")]), vec![para("Body")], ); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); let header = match &resolved.content[0] { Block::Div(d) => d, other => panic!("expected header Div, got {:?}", other), @@ -1337,7 +1356,7 @@ mod tests { Some(vec![str_inline("T")]), vec![para("Body")], ); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); let classes = outer_classes(&resolved); assert_no_class(&classes, "callout-appearance-default"); assert_no_class(&classes, "callout-appearance-simple"); @@ -1356,7 +1375,7 @@ mod tests { vec![para("Body")], ); node.attr.0 = "mywarn".to_string(); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); assert_eq!( resolved.attr.0, "mywarn", "user-supplied id must survive resolution" @@ -1374,7 +1393,7 @@ mod tests { Some(vec![str_inline("T")]), vec![para("Body")], ); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); assert_has_class(&outer_classes(&resolved), &format!("callout-{}", t)); } } @@ -1395,7 +1414,7 @@ mod tests { Some(vec![str_inline("Watch Out")]), vec![para("Body")], ); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); let header = match &resolved.content[0] { Block::Div(d) => d, other => panic!("expected header Div, got {:?}", other), @@ -1454,7 +1473,7 @@ mod tests { None, // no user title → default-inject "Tip" vec![para("Body")], ); - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); let header = match &resolved.content[0] { Block::Div(d) => d, _ => panic!("expected header Div"), @@ -1504,7 +1523,7 @@ mod tests { obj.insert("kind".into(), json!("Tip")); obj.insert("identifier".into(), json!("tip-foo")); } - let resolved = resolve_callout(&mut node, &mut 1); + let resolved = resolve_callout(&mut node, &mut 1, None); let header = match &resolved.content[0] { Block::Div(d) => d, _ => panic!("expected header Div"), diff --git a/crates/quarto-core/src/transforms/crossref_render.rs b/crates/quarto-core/src/transforms/crossref_render.rs index 3e257e8ac..b913fc16d 100644 --- a/crates/quarto-core/src/transforms/crossref_render.rs +++ b/crates/quarto-core/src/transforms/crossref_render.rs @@ -47,6 +47,7 @@ use quarto_source_map::SourceInfo; use crate::Result; use crate::crossref::{CROSSREF_RESOLVED_REF, EQUATION, FLOAT_REF_TARGET, PROOF, THEOREM}; +use crate::language::LanguageTerms; use crate::render::RenderContext; use crate::transform::{AstTransform, TransformPhase}; @@ -77,65 +78,71 @@ impl AstTransform for CrossrefRenderTransform { } async fn transform(&self, ast: &mut Pandoc, _ctx: &mut RenderContext) -> Result<()> { - render_blocks(&mut ast.blocks); + // Localized terms (bd-llhlzd7p): reference text prefers the + // `crossref--prefix` term (Q1 semantics; prefix falls back to + // title), and proof labels use `environment-proof-title`. `None` + // when the LanguageResolveStage hasn't run (direct unit tests) — + // the node's `kind` / English defaults apply then. + let terms = LanguageTerms::from_meta(&ast.meta); + render_blocks(&mut ast.blocks, terms.as_ref()); Ok(()) } } -fn render_blocks(blocks: &mut Blocks) { +fn render_blocks(blocks: &mut Blocks, terms: Option<&LanguageTerms>) { for block in blocks.iter_mut() { - render_block(block); + render_block(block, terms); } } -fn render_block(block: &mut Block) { +fn render_block(block: &mut Block, terms: Option<&LanguageTerms>) { // Recurse into children. match block { - Block::BlockQuote(bq) => render_blocks(&mut bq.content), + Block::BlockQuote(bq) => render_blocks(&mut bq.content, terms), Block::OrderedList(ol) => { for item in &mut ol.content { - render_blocks(item); + render_blocks(item, terms); } } Block::BulletList(bl) => { for item in &mut bl.content { - render_blocks(item); + render_blocks(item, terms); } } Block::DefinitionList(dl) => { for (term, defs) in &mut dl.content { - render_inlines(term); + render_inlines(term, terms); for def in defs { - render_blocks(def); + render_blocks(def, terms); } } } Block::Figure(fig) => { - render_blocks(&mut fig.content); + render_blocks(&mut fig.content, terms); if let Some(long) = fig.caption.long.as_mut() { - render_blocks(long); + render_blocks(long, terms); } if let Some(short) = fig.caption.short.as_mut() { - render_inlines(short); + render_inlines(short, terms); } } - Block::Div(div) => render_blocks(&mut div.content), - Block::Paragraph(p) => render_inlines(&mut p.content), - Block::Plain(p) => render_inlines(&mut p.content), + Block::Div(div) => render_blocks(&mut div.content, terms), + Block::Paragraph(p) => render_inlines(&mut p.content, terms), + Block::Plain(p) => render_inlines(&mut p.content, terms), Block::LineBlock(lb) => { for line in &mut lb.content { - render_inlines(line); + render_inlines(line, terms); } } - Block::Header(h) => render_inlines(&mut h.content), + Block::Header(h) => render_inlines(&mut h.content, terms), Block::Custom(node) => { // Recurse into slots first so nested resolved refs are rendered. for (_k, slot) in node.slots.iter_mut() { match slot { - Slot::Block(b) => render_block(b), - Slot::Blocks(bs) => render_blocks(bs), - Slot::Inline(i) => render_inline(i), - Slot::Inlines(is) => render_inlines(is), + Slot::Block(b) => render_block(b, terms), + Slot::Blocks(bs) => render_blocks(bs, terms), + Slot::Inline(i) => render_inline(i, terms), + Slot::Inlines(is) => render_inlines(is, terms), } } } @@ -151,7 +158,7 @@ fn render_block(block: &mut Block) { let replacement = render_theorem(take_custom_node(node)); *block = replacement; } else if node.type_name == PROOF { - let replacement = render_proof(take_custom_node(node)); + let replacement = render_proof(take_custom_node(node), terms); *block = replacement; } } @@ -172,36 +179,36 @@ fn take_custom_node(node: &mut CustomNode) -> CustomNode { ) } -fn render_inlines(inlines: &mut Inlines) { +fn render_inlines(inlines: &mut Inlines, terms: Option<&LanguageTerms>) { for inline in inlines.iter_mut() { - render_inline(inline); + render_inline(inline, terms); } } -fn render_inline(inline: &mut Inline) { +fn render_inline(inline: &mut Inline, terms: Option<&LanguageTerms>) { match inline { - Inline::Emph(e) => render_inlines(&mut e.content), - Inline::Underline(u) => render_inlines(&mut u.content), - Inline::Strong(s) => render_inlines(&mut s.content), - Inline::Strikeout(s) => render_inlines(&mut s.content), - Inline::Superscript(s) => render_inlines(&mut s.content), - Inline::Subscript(s) => render_inlines(&mut s.content), - Inline::SmallCaps(s) => render_inlines(&mut s.content), - Inline::Quoted(q) => render_inlines(&mut q.content), - Inline::Link(l) => render_inlines(&mut l.content), - Inline::Image(i) => render_inlines(&mut i.content), - Inline::Note(n) => render_blocks(&mut n.content), - Inline::Span(s) => render_inlines(&mut s.content), - Inline::Insert(i) => render_inlines(&mut i.content), - Inline::Delete(d) => render_inlines(&mut d.content), - Inline::Highlight(h) => render_inlines(&mut h.content), + Inline::Emph(e) => render_inlines(&mut e.content, terms), + Inline::Underline(u) => render_inlines(&mut u.content, terms), + Inline::Strong(s) => render_inlines(&mut s.content, terms), + Inline::Strikeout(s) => render_inlines(&mut s.content, terms), + Inline::Superscript(s) => render_inlines(&mut s.content, terms), + Inline::Subscript(s) => render_inlines(&mut s.content, terms), + Inline::SmallCaps(s) => render_inlines(&mut s.content, terms), + Inline::Quoted(q) => render_inlines(&mut q.content, terms), + Inline::Link(l) => render_inlines(&mut l.content, terms), + Inline::Image(i) => render_inlines(&mut i.content, terms), + Inline::Note(n) => render_blocks(&mut n.content, terms), + Inline::Span(s) => render_inlines(&mut s.content, terms), + Inline::Insert(i) => render_inlines(&mut i.content, terms), + Inline::Delete(d) => render_inlines(&mut d.content, terms), + Inline::Highlight(h) => render_inlines(&mut h.content, terms), Inline::Custom(node) => { for (_k, slot) in node.slots.iter_mut() { match slot { - Slot::Block(b) => render_block(b), - Slot::Blocks(bs) => render_blocks(bs), - Slot::Inline(i) => render_inline(i), - Slot::Inlines(is) => render_inlines(is), + Slot::Block(b) => render_block(b, terms), + Slot::Blocks(bs) => render_blocks(bs, terms), + Slot::Inline(i) => render_inline(i, terms), + Slot::Inlines(is) => render_inlines(is, terms), } } } @@ -210,7 +217,7 @@ fn render_inline(inline: &mut Inline) { if let Inline::Custom(node) = inline { if node.type_name == CROSSREF_RESOLVED_REF { - *inline = render_resolved_ref(take_custom_node(node)); + *inline = render_resolved_ref(take_custom_node(node), terms); } else if node.type_name == EQUATION { *inline = render_equation(take_custom_node(node)); } @@ -535,7 +542,7 @@ fn prepend_theorem_label(mut content: Blocks, label: Inlines, source_info: Sourc /// /// Proofs never carry a number. The id (if any) flows through on the /// Div's `id` attribute so anchor links still work. -fn render_proof(node: CustomNode) -> Block { +fn render_proof(node: CustomNode, terms: Option<&LanguageTerms>) -> Block { let source_info = node.source_info.clone(); let mut attr = node.attr; if !attr.1.iter().any(|c| c == "proof") { @@ -562,10 +569,17 @@ fn render_proof(node: CustomNode) -> Block { })); inlines } - None => vec![Inline::Str(Str { - text: "Proof.".to_string(), - source_info: source_info.clone(), - })], + None => { + // `environment-proof-title` term ("Proof" → "Demostración", …); + // the trailing period matches Q1's proof label shape. + let proof_title = terms + .and_then(|t| t.get("environment-proof-title")) + .unwrap_or("Proof"); + vec![Inline::Str(Str { + text: format!("{proof_title}."), + source_info: source_info.clone(), + })] + } }; // Make the label italic via Emph. let label: Inlines = vec![ @@ -658,19 +672,32 @@ fn render_equation(node: CustomNode) -> Inline { /// Link text is `" "` when the ref is resolved, or the literal /// `"?id?"` (wrapped visibly) for unresolved refs so the failure is /// obvious in the rendered document. -fn render_resolved_ref(node: CustomNode) -> Inline { +fn render_resolved_ref(node: CustomNode, terms: Option<&LanguageTerms>) -> Inline { let identifier = node .plain_data .get("identifier") .and_then(|v| v.as_str()) .unwrap_or("") .to_string(); - let kind = node + // Reference text uses the `crossref--prefix` term (which falls + // back to `crossref--title`) when the language table defines one; + // otherwise the node's `kind` (registry display name — already + // localized for built-ins, or `crossref.custom`'s reference-prefix). + let ref_type = node .plain_data - .get("kind") + .get("ref_type") .and_then(|v| v.as_str()) - .unwrap_or("") - .to_string(); + .unwrap_or(""); + let kind = terms.and_then(|t| t.crossref_prefix(ref_type)).map_or_else( + || { + node.plain_data + .get("kind") + .and_then(|v| v.as_str()) + .unwrap_or("") + .to_string() + }, + |s| s.to_string(), + ); let resolved = node .plain_data .get("resolved") @@ -1064,7 +1091,7 @@ mod tests { .slots .insert("content".into(), Slot::Blocks(vec![para("inside")])); let mut block = Block::Custom(callout); - render_block(&mut block); + render_block(&mut block, None); match block { Block::Custom(n) => assert_eq!(n.type_name, "Callout"), _ => panic!("callout was mutated"), diff --git a/crates/quarto-core/src/transforms/theorem.rs b/crates/quarto-core/src/transforms/theorem.rs index 34025e5eb..16b005830 100644 --- a/crates/quarto-core/src/transforms/theorem.rs +++ b/crates/quarto-core/src/transforms/theorem.rs @@ -189,6 +189,13 @@ fn transform_block( let matched = class_match.or(id_match); if let Some((ref_type, kind)) = matched { + // Display name from the registry when available — its built-in + // kinds are localized by the pre-engine-sugaring stage + // (bd-llhlzd7p). The static table's English name is the + // registry-less fallback (direct unit tests). + let kind = registry + .and_then(|r| r.get(ref_type)) + .map_or_else(|| kind.to_string(), |def| def.kind.clone()); let converted = convert_div( std::mem::replace( div, @@ -200,7 +207,7 @@ fn transform_block( }, ), ref_type, - kind, + &kind, ); *block = Block::Custom(converted); } diff --git a/crates/quarto-core/src/transforms/toc_generate.rs b/crates/quarto-core/src/transforms/toc_generate.rs index 1811f09ff..01a9a5d89 100644 --- a/crates/quarto-core/src/transforms/toc_generate.rs +++ b/crates/quarto-core/src/transforms/toc_generate.rs @@ -118,13 +118,19 @@ impl AstTransform for TocGenerateTransform { .and_then(|v| v.as_int()) .unwrap_or(3) as i32; - // Default title is "Table of Contents" if not specified. + // Title precedence (decided 2026-07-17, bd-llhlzd7p): user + // `toc-title` metadata > localized `toc-title-document` term > + // English literal (stage-less unit-test fallback). // `as_plain_text` (not `as_str`): a bare `toc-title` front-matter string // is stored as `ConfigValueKind::PandocInlines`. (bd-y89ihf0i) let title = ast .meta .get("toc-title") .and_then(|v| v.as_plain_text()) + .or_else(|| { + crate::language::LanguageTerms::from_meta(&ast.meta) + .and_then(|t| t.get("toc-title-document").map(|s| s.to_string())) + }) .or_else(|| Some("Table of Contents".to_string())); let config = TocConfig { depth, title }; diff --git a/crates/quarto-core/tests/integration/language_catalog.rs b/crates/quarto-core/tests/integration/language_catalog.rs new file mode 100644 index 000000000..d210a58a7 --- /dev/null +++ b/crates/quarto-core/tests/integration/language_catalog.rs @@ -0,0 +1,126 @@ +//! Catalog integrity tests for the embedded language term files +//! (`resources/language/_language*.yml`). +//! +//! These guard the re-copy workflow documented in `resources/language/README.md`: +//! if an upstream update introduces malformed files, non-string values, or new +//! stray keys, these tests fail and prompt a review. +//! +//! Part of the localization epic bd-llhlzd7p +//! (`claude-notes/plans/2026-07-17-localization-i18n-design.md`). + +use quarto_core::language::{ + BASE_LANGUAGE_FILE, embedded_language_file, embedded_language_file_names, parse_term_file, +}; + +/// Keys present in upstream per-language files but absent from the base +/// catalog. These are dead entries upstream (Quarto 1 silently filters +/// unknown keys); we keep our copies verbatim for provenance fidelity. +/// A new entry appearing here after a re-copy deserves a look — it is +/// either an upstream typo or a new key missing from `_language.yml`. +const KNOWN_UPSTREAM_STRAYS: &[(&str, &str)] = &[ + ("_language-lt.yml", "search"), + ("_language-sv.yml", "callout-danger-title"), +]; + +fn is_crossref_pattern(key: &str) -> bool { + key.starts_with("crossref-") && (key.ends_with("-title") || key.ends_with("-prefix")) +} + +#[test] +fn embedded_catalog_has_expected_shape() { + let names = embedded_language_file_names(); + assert!( + names.contains(&BASE_LANGUAGE_FILE), + "base {BASE_LANGUAGE_FILE} must be embedded" + ); + // 34 per-language variants shipped from Quarto 1 at the time of the copy. + let variants = names.iter().filter(|n| **n != BASE_LANGUAGE_FILE).count(); + assert_eq!( + variants, 34, + "expected exactly 34 per-language files, found {variants}: {names:?}" + ); +} + +#[test] +fn base_catalog_contains_keys_consumed_by_transforms() { + let base = parse_term_file( + embedded_language_file(BASE_LANGUAGE_FILE).expect("base file embedded"), + BASE_LANGUAGE_FILE, + ) + .expect("base file parses"); + + // Keys the v1 consumers depend on (plan section D4). Exact values are + // asserted so a silent upstream rename/redefinition fails loudly. + let expected = [ + ("callout-note-title", "Note"), + ("callout-tip-title", "Tip"), + ("callout-warning-title", "Warning"), + ("callout-important-title", "Important"), + ("callout-caution-title", "Caution"), + ("crossref-fig-title", "Figure"), + ("crossref-tbl-title", "Table"), + ("crossref-lst-title", "Listing"), + ("crossref-eq-prefix", "Equation"), + ("crossref-sec-prefix", "Section"), + ("crossref-thm-title", "Theorem"), + ("crossref-lem-title", "Lemma"), + ("crossref-cor-title", "Corollary"), + ("crossref-prp-title", "Proposition"), + ("crossref-cnj-title", "Conjecture"), + ("crossref-def-title", "Definition"), + ("crossref-exm-title", "Example"), + ("crossref-exr-title", "Exercise"), + ("environment-proof-title", "Proof"), + ("environment-solution-title", "Solution"), + ("environment-remark-title", "Remark"), + ("toc-title-document", "Table of contents"), + ("section-title-abstract", "Abstract"), + ("title-block-author-single", "Author"), + ("title-block-author-plural", "Authors"), + ("title-block-published", "Published"), + ]; + for (key, value) in expected { + assert_eq!( + base.terms.get(key).map(|t| t.value.as_str()), + Some(value), + "base catalog key {key:?}" + ); + } +} + +#[test] +fn every_embedded_file_is_a_flat_string_map_with_known_keys() { + let base = parse_term_file( + embedded_language_file(BASE_LANGUAGE_FILE).expect("base file embedded"), + BASE_LANGUAGE_FILE, + ) + .expect("base file parses"); + + for name in embedded_language_file_names() { + let content = embedded_language_file(name).expect("listed file is readable"); + let layer = parse_term_file(content, name) + .unwrap_or_else(|e| panic!("{name} failed to parse as a term file: {e}")); + assert!( + !layer.terms.is_empty(), + "{name} parsed to an empty term map" + ); + if name == BASE_LANGUAGE_FILE { + continue; + } + for key in layer.terms.keys() { + let known = base.terms.contains_key(key.as_str()) + || is_crossref_pattern(key) + || KNOWN_UPSTREAM_STRAYS.contains(&(name, key.as_str())); + assert!( + known, + "{name}: key {key:?} is not in the base catalog, does not match \ + crossref-*-title/-prefix, and is not a documented upstream stray" + ); + } + } +} + +// Note: variant files do NOT always have a parent file — upstream ships +// `_language-sr-Latn.yml` with no `_language-sr.yml`. The subtag walk must +// tolerate missing intermediate layers; that behavior is unit-tested with the +// resolution engine (phase 2 of the plan). diff --git a/crates/quarto-core/tests/integration/language_pipeline.rs b/crates/quarto-core/tests/integration/language_pipeline.rs new file mode 100644 index 000000000..c70dc9f99 --- /dev/null +++ b/crates/quarto-core/tests/integration/language_pipeline.rs @@ -0,0 +1,285 @@ +//! Pipeline-level tests for `LanguageResolveStage` (localization, bd-llhlzd7p). +//! +//! The stage runs immediately after `metadata-merge`, resolves the document's +//! term table from `lang` + `language:` metadata (+ project-root +//! `_language.yml`), and injects it into `doc.ast.meta` under +//! `quarto.language` — the single transport consumed by transforms +//! (`LanguageTerms::from_meta`) and templates (`$quarto.language.$`). + +use std::path::PathBuf; +use std::sync::Arc; + +use quarto_core::format::Format; +use quarto_core::language::LanguageTerms; +use quarto_core::pipeline::{build_html_pipeline_stages, build_wasm_html_pipeline}; +use quarto_core::project::{DocumentInfo, ProjectConfig, ProjectContext}; +use quarto_core::stage::{ + LoadedSource, Pipeline, PipelineData, PipelineDataKind, PipelineStage, StageContext, +}; +use quarto_error_reporting::DiagnosticKind; +use quarto_pandoc_types::ConfigValue; + +fn make_context(project_dir: PathBuf, doc_path: PathBuf, is_single_file: bool) -> StageContext { + let runtime = Arc::new(quarto_system_runtime::NativeRuntime::new()); + let format = Format::html(); + let project = ProjectContext { + dir: project_dir.clone(), + config: ProjectConfig::default(), + is_single_file, + files: vec![DocumentInfo::from_path(doc_path.clone())], + output_dir: project_dir, + }; + let document = DocumentInfo::from_path(doc_path); + StageContext::new(runtime, format, project, document).expect("stage context") +} + +/// Run the html pipeline stages up to and including `language-resolve`, +/// returning the post-stage metadata and the collected diagnostics. +async fn run_through_language_resolve( + content: &[u8], + ctx: &mut StageContext, + doc_path: PathBuf, +) -> ConfigValue { + let full = build_html_pipeline_stages(); + let pos = full + .iter() + .position(|s| s.name() == "language-resolve") + .expect("language-resolve stage present in html pipeline"); + let head: Vec> = full.into_iter().take(pos + 1).collect(); + let pipeline = Pipeline::new(head).expect("head pipeline valid"); + let input = PipelineData::LoadedSource(LoadedSource::new(doc_path, content.to_vec())); + let out = pipeline.run(input, ctx).await.expect("pipeline runs"); + assert_eq!(out.kind(), PipelineDataKind::DocumentAst); + out.into_document_ast().unwrap().ast.meta +} + +/// Convenience: run in a synthetic cwd-based single-file context. +async fn run_simple(content: &[u8]) -> (ConfigValue, StageContext) { + let dir = std::env::current_dir().unwrap(); + let doc = dir.join("test.qmd"); + let mut ctx = make_context(dir, doc.clone(), true); + let meta = run_through_language_resolve(content, &mut ctx, doc).await; + (meta, ctx) +} + +fn quarto_language_term(meta: &ConfigValue, key: &str) -> Option { + meta.get("quarto")? + .get("language")? + .get(key)? + .as_plain_text() +} + +// ── Stage placement ──────────────────────────────────────────────────────── + +#[test] +fn pipelines_run_language_resolve_right_after_metadata_merge() { + let stages = build_html_pipeline_stages(); + let names: Vec<&str> = stages.iter().map(|s| s.name()).collect(); + let merge = names + .iter() + .position(|n| *n == "metadata-merge") + .expect("metadata-merge present"); + assert_eq!( + names.get(merge + 1).copied(), + Some("language-resolve"), + "language-resolve must directly follow metadata-merge: {names:?}" + ); + + let wasm_pipeline = build_wasm_html_pipeline(); + let wasm_names = wasm_pipeline.stage_names(); + let wasm_merge = wasm_names + .iter() + .position(|n| *n == "metadata-merge") + .expect("metadata-merge present in wasm pipeline"); + assert_eq!( + wasm_names.get(wasm_merge + 1).copied(), + Some("language-resolve"), + "wasm pipeline must include language-resolve after metadata-merge: {wasm_names:?}" + ); +} + +// ── Meta injection ───────────────────────────────────────────────────────── + +#[tokio::test] +async fn lang_es_injects_spanish_terms_into_meta() { + let (meta, ctx) = run_simple(b"---\nlang: es\n---\n\nHello.\n").await; + assert_eq!( + quarto_language_term(&meta, "callout-note-title").as_deref(), + Some("Nota") + ); + assert_eq!( + quarto_language_term(&meta, "toc-title-document").as_deref(), + Some("Tabla de contenidos") + ); + assert!( + ctx.diagnostics.is_empty(), + "no diagnostics expected: {:?}", + ctx.diagnostics + ); +} + +#[tokio::test] +async fn no_lang_defaults_to_english_terms() { + let (meta, _) = run_simple(b"---\ntitle: T\n---\n\nHello.\n").await; + assert_eq!( + quarto_language_term(&meta, "callout-note-title").as_deref(), + Some("Note") + ); +} + +#[tokio::test] +async fn from_meta_round_trips_resolved_terms() { + let (meta, _) = run_simple(b"---\nlang: pt-BR\n---\n\nHello.\n").await; + let terms = LanguageTerms::from_meta(&meta).expect("quarto.language present"); + assert_eq!(terms.lang(), "pt-BR"); + assert_eq!(terms.get("code-links-title"), Some("Links de código")); + assert_eq!(terms.crossref_prefix("fig"), Some("Figura")); +} + +#[tokio::test] +async fn inline_language_map_overrides_shipped_terms() { + let src = b"---\nlang: fr\nlanguage:\n toc-title-document: \"Sommaire\"\n---\n\nBonjour.\n"; + let (meta, ctx) = run_simple(src).await; + assert_eq!( + quarto_language_term(&meta, "toc-title-document").as_deref(), + Some("Sommaire") + ); + // Untouched keys keep shipped fr values. + assert_eq!( + quarto_language_term(&meta, "title-block-published").as_deref(), + Some("Date de publication") + ); + assert!(ctx.diagnostics.is_empty()); +} + +#[tokio::test] +async fn unknown_language_key_warns_through_stage_diagnostics() { + let src = b"---\nlanguage:\n my-custom-term: \"Zap\"\n---\n\nHello.\n"; + let (meta, ctx) = run_simple(src).await; + let warnings: Vec<_> = ctx + .diagnostics + .iter() + .filter(|d| d.kind == DiagnosticKind::Warning) + .collect(); + assert_eq!(warnings.len(), 1, "one warning expected: {warnings:?}"); + assert!(warnings[0].title.contains("my-custom-term")); + // The custom term is still resolvable. + assert_eq!( + quarto_language_term(&meta, "my-custom-term").as_deref(), + Some("Zap") + ); +} + +// ── File-based language config ───────────────────────────────────────────── + +fn scratch_dir(name: &str) -> PathBuf { + let dir = std::env::temp_dir() + .join("q2-language-pipeline-tests") + .join(name); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(&dir).expect("create scratch dir"); + dir +} + +#[tokio::test] +async fn language_file_resolves_relative_to_document() { + let dir = scratch_dir("file-form"); + std::fs::write( + dir.join("custom.yml"), + "toc-title-document: \"Custom TOC\"\n", + ) + .unwrap(); + let doc = dir.join("test.qmd"); + let mut ctx = make_context(dir, doc.clone(), true); + let meta = + run_through_language_resolve(b"---\nlanguage: custom.yml\n---\n\nHello.\n", &mut ctx, doc) + .await; + assert_eq!( + quarto_language_term(&meta, "toc-title-document").as_deref(), + Some("Custom TOC") + ); + assert!( + ctx.diagnostics.is_empty(), + "no diagnostics expected: {:?}", + ctx.diagnostics + ); +} + +#[tokio::test] +async fn missing_language_file_is_an_error_diagnostic() { + let dir = scratch_dir("missing-file"); + let doc = dir.join("test.qmd"); + let mut ctx = make_context(dir, doc.clone(), true); + let meta = + run_through_language_resolve(b"---\nlanguage: nope.yml\n---\n\nHello.\n", &mut ctx, doc) + .await; + let errors: Vec<_> = ctx + .diagnostics + .iter() + .filter(|d| d.kind == DiagnosticKind::Error) + .collect(); + assert_eq!(errors.len(), 1, "one error expected: {:?}", ctx.diagnostics); + assert!( + errors[0].title.contains("nope.yml"), + "error should name the file: {}", + errors[0].title + ); + // Shipped terms still resolve (render continues usable). + assert_eq!( + quarto_language_term(&meta, "callout-note-title").as_deref(), + Some("Note") + ); +} + +#[tokio::test] +async fn project_root_language_yml_is_autodetected() { + let dir = scratch_dir("project-root"); + std::fs::write( + dir.join("_language.yml"), + "toc-title-document: \"Project TOC\"\n", + ) + .unwrap(); + std::fs::write( + dir.join("_language-fr.yml"), + "toc-title-document: \"TOC projet\"\n", + ) + .unwrap(); + let doc = dir.join("test.qmd"); + + // lang: fr picks the sibling _language-fr.yml value. + let mut ctx = make_context(dir.clone(), doc.clone(), false); + let meta = + run_through_language_resolve(b"---\nlang: fr\n---\n\nBonjour.\n", &mut ctx, doc.clone()) + .await; + assert_eq!( + quarto_language_term(&meta, "toc-title-document").as_deref(), + Some("TOC projet") + ); + + // Without lang, the project base file applies. + let mut ctx2 = make_context(dir, doc.clone(), false); + let meta2 = + run_through_language_resolve(b"---\ntitle: T\n---\n\nHello.\n", &mut ctx2, doc).await; + assert_eq!( + quarto_language_term(&meta2, "toc-title-document").as_deref(), + Some("Project TOC") + ); +} + +#[tokio::test] +async fn single_file_render_ignores_project_root_language_yml() { + // Auto-detection is a project feature (Q1: "alongside _quarto.yml"). + let dir = scratch_dir("single-file"); + std::fs::write( + dir.join("_language.yml"), + "toc-title-document: \"Should not apply\"\n", + ) + .unwrap(); + let doc = dir.join("test.qmd"); + let mut ctx = make_context(dir, doc.clone(), true); + let meta = run_through_language_resolve(b"---\ntitle: T\n---\n\nHello.\n", &mut ctx, doc).await; + assert_eq!( + quarto_language_term(&meta, "toc-title-document").as_deref(), + Some("Table of contents") + ); +} diff --git a/crates/quarto-core/tests/integration/language_resolve.rs b/crates/quarto-core/tests/integration/language_resolve.rs new file mode 100644 index 000000000..01bea2544 --- /dev/null +++ b/crates/quarto-core/tests/integration/language_resolve.rs @@ -0,0 +1,268 @@ +//! Unit tests for language term resolution (localization). +//! +//! Covers the merge semantics defined in +//! `claude-notes/plans/2026-07-17-localization-i18n-design.md` (bd-llhlzd7p): +//! shipped-file subtag walk, user `language:` overrides (plain keys, +//! per-language subkeys, custom files), crossref prefix→title fallback, and +//! unknown-key warnings. + +use pampa::utils::diagnostic_collector::DiagnosticCollector; +use quarto_core::language::{ + StructuredTermLayer, parse_language_file, resolve_language, structured_layer_from_config, +}; +use quarto_error_reporting::DiagnosticKind; + +/// Parses YAML as document front matter (strings become PandocInlines, the +/// same shape a real `language:` block has after metadata merging) and +/// converts it to a structured term layer. +fn user_layer(yaml: &str) -> (StructuredTermLayer, DiagnosticCollector) { + let parsed = quarto_yaml::parse(yaml).expect("test yaml parses"); + let mut diagnostics = DiagnosticCollector::new(); + let config = pampa::pandoc::yaml_to_config_value( + parsed, + quarto_config::InterpretationContext::DocumentMetadata, + &mut diagnostics, + ); + assert!( + diagnostics.diagnostics().is_empty(), + "yaml conversion should not diagnose: {:?}", + diagnostics.diagnostics() + ); + let mut layer_diags = DiagnosticCollector::new(); + let layer = structured_layer_from_config(&config, &mut layer_diags); + (layer, layer_diags) +} + +fn resolve_no_extras(lang: &str) -> quarto_core::language::LanguageTerms { + resolve_language(lang, &[]) +} + +// ── Shipped-file resolution ──────────────────────────────────────────────── + +#[test] +fn english_base_resolves() { + let terms = resolve_no_extras("en"); + assert_eq!(terms.lang(), "en"); + assert_eq!(terms.get("crossref-fig-title"), Some("Figure")); + assert_eq!(terms.get("toc-title-document"), Some("Table of contents")); + // Empty-string term values are legal (and distinct from absent). + assert_eq!(terms.get("search-text-placeholder"), Some("")); + assert_eq!(terms.get("no-such-term"), None); +} + +#[test] +fn plain_language_tag_resolves_shipped_translation() { + let terms = resolve_no_extras("es"); + assert_eq!(terms.get("callout-note-title"), Some("Nota")); + assert_eq!(terms.get("crossref-fig-title"), Some("Figura")); + assert_eq!(terms.get("toc-title-document"), Some("Tabla de contenidos")); + assert_eq!(terms.get("environment-proof-title"), Some("Demostración")); +} + +#[test] +fn subtag_walk_merges_most_general_first() { + let terms = resolve_no_extras("pt-BR"); + // Overridden in _language-pt-BR.yml: + assert_eq!(terms.get("code-links-title"), Some("Links de código")); + // Only in _language-pt.yml (inherited through the walk): + assert_eq!( + terms.get("title-block-modified"), + Some("Data de Modificação") + ); + // Plain pt keeps its own value when asked for directly: + let pt = resolve_no_extras("pt"); + assert_eq!(pt.get("code-links-title"), Some("Ligações de código")); +} + +#[test] +fn region_and_script_variants_resolve() { + let de_ch = resolve_no_extras("de-CH"); + assert_eq!(de_ch.get("section-title-footnotes"), Some("Fussnoten")); + // Inherited from _language-de.yml: + assert_eq!(de_ch.get("crossref-fig-title"), Some("Abbildung")); + + let zh_tw = resolve_no_extras("zh-TW"); + assert_eq!(zh_tw.get("callout-note-title"), Some("註釋")); +} + +#[test] +fn missing_intermediate_layer_is_tolerated() { + // Upstream ships _language-sr-Latn.yml with no _language-sr.yml. + let terms = resolve_no_extras("sr-Latn"); + assert_eq!(terms.get("callout-note-title"), Some("Beleška")); +} + +#[test] +fn unknown_region_falls_back_to_parent_language() { + let terms = resolve_no_extras("es-MX"); + assert_eq!(terms.get("callout-note-title"), Some("Nota")); +} + +#[test] +fn unknown_language_falls_back_to_english() { + let terms = resolve_no_extras("xx"); + assert_eq!(terms.get("callout-note-title"), Some("Note")); + assert_eq!(terms.get("crossref-fig-title"), Some("Figure")); +} + +// ── Crossref accessor fallbacks ──────────────────────────────────────────── + +#[test] +fn crossref_prefix_falls_back_to_title() { + let en = resolve_no_extras("en"); + // fig has no crossref-fig-prefix in the catalog: falls back to the title. + assert_eq!(en.crossref_prefix("fig"), Some("Figure")); + // eq has an explicit prefix key. + assert_eq!(en.crossref_prefix("eq"), Some("Equation")); + assert_eq!(en.crossref_title("fig"), Some("Figure")); + assert_eq!(en.crossref_title("nosuchtype"), None); + assert_eq!(en.crossref_prefix("nosuchtype"), None); + + let es = resolve_no_extras("es"); + assert_eq!(es.crossref_prefix("fig"), Some("Figura")); + assert_eq!(es.crossref_prefix("eq"), Some("Ecuación")); +} + +// ── User overrides ───────────────────────────────────────────────────────── + +#[test] +fn user_plain_key_overrides_shipped_translation() { + let (layer, diags) = user_layer("toc-title-document: \"Sommaire\"\n"); + assert!(diags.diagnostics().is_empty()); + let terms = resolve_language("fr", &[layer]); + assert_eq!(terms.get("toc-title-document"), Some("Sommaire")); + // Untouched keys keep the shipped fr values. + assert_eq!( + terms.get("title-block-published"), + Some("Date de publication") + ); +} + +#[test] +fn user_subkeys_apply_only_for_matching_lang() { + let yaml = "\ +en: + title-block-published: \"Updated\" +fr: + title-block-published: \"Mis à jour!\" +"; + let (layer, _) = user_layer(yaml); + let fr = resolve_language("fr", std::slice::from_ref(&layer)); + assert_eq!(fr.get("title-block-published"), Some("Mis à jour!")); + + let en = resolve_language("en", std::slice::from_ref(&layer)); + assert_eq!(en.get("title-block-published"), Some("Updated")); + + // fr-CA walks through fr, picking up the fr subkey. + let fr_ca = resolve_language("fr-CA", &[layer]); + assert_eq!(fr_ca.get("title-block-published"), Some("Mis à jour!")); +} + +#[test] +fn user_subkey_beats_plain_key_within_a_layer() { + let yaml = "\ +title-block-published: \"Plain\" +fr: + title-block-published: \"Subkey\" +"; + let (layer, _) = user_layer(yaml); + let fr = resolve_language("fr", std::slice::from_ref(&layer)); + assert_eq!(fr.get("title-block-published"), Some("Subkey")); + // For a non-matching lang the plain key still applies. + let es = resolve_language("es", &[layer]); + assert_eq!(es.get("title-block-published"), Some("Plain")); +} + +#[test] +fn later_layers_override_earlier_layers() { + let (project, _) = user_layer("toc-title-document: \"From project\"\n"); + let (doc, _) = user_layer("toc-title-document: \"From doc\"\n"); + let terms = resolve_language("en", &[project, doc]); + assert_eq!(terms.get("toc-title-document"), Some("From doc")); +} + +// ── Unknown-key warnings ─────────────────────────────────────────────────── + +#[test] +fn unknown_key_warns_but_is_preserved() { + let (layer, diags) = user_layer("my-custom-term: \"Zap\"\n"); + let warnings: Vec<_> = diags + .diagnostics() + .iter() + .filter(|d| d.kind == DiagnosticKind::Warning) + .collect(); + assert_eq!(warnings.len(), 1, "expected one warning: {warnings:?}"); + assert!( + warnings[0].title.contains("my-custom-term"), + "warning should name the key: {}", + warnings[0].title + ); + assert!( + warnings[0].location.is_some(), + "warning should carry a source location" + ); + + // The key is still resolvable (usable from custom templates). + let terms = resolve_language("en", &[layer]); + assert_eq!(terms.get("my-custom-term"), Some("Zap")); +} + +#[test] +fn custom_crossref_pattern_keys_do_not_warn() { + let (_, diags) = + user_layer("crossref-robot-title: \"Robot\"\ncrossref-robot-prefix: \"Rbt.\"\n"); + assert!( + diags.diagnostics().is_empty(), + "crossref-*-title/-prefix are legal for custom types: {:?}", + diags.diagnostics() + ); +} + +#[test] +fn unknown_key_inside_subkey_warns_too() { + let (_, diags) = user_layer("fr:\n my-custom-term: \"Zap\"\n"); + let warnings: Vec<_> = diags + .diagnostics() + .iter() + .filter(|d| d.kind == DiagnosticKind::Warning) + .collect(); + assert_eq!(warnings.len(), 1); +} + +// ── Custom language files ────────────────────────────────────────────────── + +#[test] +fn custom_file_flat_form() { + // Q1 docs: a full-translation custom.yml is a flat term map. + let content = "callout-note-title: \"Nota Bene\"\ntoc-title-document: \"Indice\"\n"; + let mut file_diags = DiagnosticCollector::new(); + let layer = parse_language_file(content, "custom.yml", &mut file_diags).expect("parses"); + let terms = resolve_language("en", &[layer]); + assert_eq!(terms.get("callout-note-title"), Some("Nota Bene")); + assert_eq!(terms.get("toc-title-document"), Some("Indice")); + // Untouched keys fall through to the shipped base. + assert_eq!(terms.get("callout-tip-title"), Some("Tip")); +} + +#[test] +fn custom_file_per_language_form() { + // Q1 docs example (custom-language.yml). + let content = "\ +en: + title-block-published: \"Updated\" +fr: + title-block-published: \"Mis à jour\" +"; + let mut file_diags = DiagnosticCollector::new(); + let layer = + parse_language_file(content, "custom-language.yml", &mut file_diags).expect("parses"); + let fr = resolve_language("fr", &[layer]); + assert_eq!(fr.get("title-block-published"), Some("Mis à jour")); +} + +#[test] +fn custom_file_rejects_non_string_values() { + let mut file_diags = DiagnosticCollector::new(); + let err = parse_language_file("callout-note-title: [1, 2]\n", "bad.yml", &mut file_diags); + assert!(err.is_err(), "arrays are not legal term values"); +} diff --git a/crates/quarto-core/tests/integration/main.rs b/crates/quarto-core/tests/integration/main.rs index 33b3de3ce..8be026342 100644 --- a/crates/quarto-core/tests/integration/main.rs +++ b/crates/quarto-core/tests/integration/main.rs @@ -25,6 +25,9 @@ pub mod idempotence; pub mod include_resolve_pipeline; pub mod incremental_rebuild; pub mod jupyter_integration; +pub mod language_catalog; +pub mod language_pipeline; +pub mod language_resolve; pub mod link_rewriting_pipeline; pub mod listing_pipeline; pub mod math_mode_pipeline; diff --git a/crates/quarto-core/tests/integration/revealjs_format.rs b/crates/quarto-core/tests/integration/revealjs_format.rs index 892657147..e7db14374 100644 --- a/crates/quarto-core/tests/integration/revealjs_format.rs +++ b/crates/quarto-core/tests/integration/revealjs_format.rs @@ -764,3 +764,24 @@ format: "theme: dark should use light text" ); } + +/// The scaffold's `` follows the document's `lang` option +/// (bd-llhlzd7p); it was previously hardcoded to `"en"`. +#[test] +fn scaffold_html_lang_follows_document_lang() { + let html = render_revealjs( + "---\ntitle: \"Charla\"\nlang: es\nformat: revealjs\n---\n\n## Una\n\nHola.\n", + ); + assert!( + html.contains(""), + "expected in scaffold" + ); + + // Without `lang`, the scaffold keeps the historical "en" default. + let default_html = + render_revealjs("---\ntitle: \"Talk\"\nformat: revealjs\n---\n\n## One\n\nHi.\n"); + assert!( + default_html.contains(""), + "expected default in scaffold" + ); +} diff --git a/crates/quarto/tests/smoke-all/localization/_quarto.yml b/crates/quarto/tests/smoke-all/localization/_quarto.yml new file mode 100644 index 000000000..b939ea036 --- /dev/null +++ b/crates/quarto/tests/smoke-all/localization/_quarto.yml @@ -0,0 +1,2 @@ +project: + title: Localization Tests diff --git a/crates/quarto/tests/smoke-all/localization/lang-es-authors-plural.qmd b/crates/quarto/tests/smoke-all/localization/lang-es-authors-plural.qmd new file mode 100644 index 000000000..c5e1765bf --- /dev/null +++ b/crates/quarto/tests/smoke-all/localization/lang-es-authors-plural.qmd @@ -0,0 +1,17 @@ +--- +title: Autores múltiples +author: + - Ana García + - Luis Pérez +lang: es +format: html +_quarto: + tests: + html: + noErrors: true + ensureFileRegexMatches: + - ["Autores/as<"] + - [">Authors<", "Autor/a<"] +--- + +Contenido. diff --git a/crates/quarto/tests/smoke-all/localization/lang-es-callout.qmd b/crates/quarto/tests/smoke-all/localization/lang-es-callout.qmd new file mode 100644 index 000000000..3c1545372 --- /dev/null +++ b/crates/quarto/tests/smoke-all/localization/lang-es-callout.qmd @@ -0,0 +1,16 @@ +--- +title: Callout localization +lang: es +format: html +_quarto: + tests: + html: + noErrors: true + ensureFileRegexMatches: + - ["Nota"] + - [">Note<"] +--- + +::: {.callout-note} +Contenido de la nota. +::: diff --git a/crates/quarto/tests/smoke-all/localization/lang-es-crossref.qmd b/crates/quarto/tests/smoke-all/localization/lang-es-crossref.qmd new file mode 100644 index 000000000..c2d75d926 --- /dev/null +++ b/crates/quarto/tests/smoke-all/localization/lang-es-crossref.qmd @@ -0,0 +1,23 @@ +--- +title: Crossref localization +lang: es +format: html +_quarto: + tests: + html: + noErrors: true + ensureFileRegexMatches: + - ["Tabla 1: Una tabla", "Tabla.1"] + - [">Table<", "Table 1"] +--- + +Ver @tbl-uno. + +::: {#tbl-uno} + +| a | b | +|---|---| +| 1 | 2 | + +Una tabla +::: diff --git a/crates/quarto/tests/smoke-all/localization/lang-es-theorem.qmd b/crates/quarto/tests/smoke-all/localization/lang-es-theorem.qmd new file mode 100644 index 000000000..6f04b4d2a --- /dev/null +++ b/crates/quarto/tests/smoke-all/localization/lang-es-theorem.qmd @@ -0,0 +1,22 @@ +--- +title: Teoremas +lang: es +format: html +_quarto: + tests: + html: + noErrors: true + ensureFileRegexMatches: + - ["Teorema.1", "Demostración."] + - ["Theorem.1", ">Proof."] +--- + +::: {#thm-pit .theorem} +## Pitágoras + +Un enunciado. +::: + +::: {.proof} +Se deja como ejercicio. +::: diff --git a/crates/quarto/tests/smoke-all/localization/lang-es-title-block.qmd b/crates/quarto/tests/smoke-all/localization/lang-es-title-block.qmd new file mode 100644 index 000000000..995345b0d --- /dev/null +++ b/crates/quarto/tests/smoke-all/localization/lang-es-title-block.qmd @@ -0,0 +1,18 @@ +--- +title: Bloque de título +author: Ana García +date: 2026-01-15 +abstract: | + Un resumen breve. +lang: es +format: html +_quarto: + tests: + html: + noErrors: true + ensureFileRegexMatches: + - ["Resumen<"] + - [">Author<", ">Published<", ">Abstract<"] +--- + +Contenido. diff --git a/crates/quarto/tests/smoke-all/localization/lang-fr-toc.qmd b/crates/quarto/tests/smoke-all/localization/lang-fr-toc.qmd new file mode 100644 index 000000000..bb2a43bd1 --- /dev/null +++ b/crates/quarto/tests/smoke-all/localization/lang-fr-toc.qmd @@ -0,0 +1,21 @@ +--- +title: TOC localization +lang: fr +format: html +toc: true +_quarto: + tests: + html: + noErrors: true + ensureFileRegexMatches: + - ["Table des matières"] + - ["Table of Contents"] +--- + +# Première + +Texte. + +# Deuxième + +Texte. diff --git a/crates/quarto/tests/smoke-all/localization/language-inline-override.qmd b/crates/quarto/tests/smoke-all/localization/language-inline-override.qmd new file mode 100644 index 000000000..98108afc8 --- /dev/null +++ b/crates/quarto/tests/smoke-all/localization/language-inline-override.qmd @@ -0,0 +1,24 @@ +--- +title: Inline language override +format: html +language: + crossref-tbl-title: "Tabella" +_quarto: + tests: + html: + noErrors: true + ensureFileRegexMatches: + - ["Tabella 1: Una tabella"] + - ["Table 1:"] +--- + +Vedi @tbl-uno. + +::: {#tbl-uno} + +| a | b | +|---|---| +| 1 | 2 | + +Una tabella +::: diff --git a/docs/_quarto.yml b/docs/_quarto.yml index ac9cb5455..b43378445 100644 --- a/docs/_quarto.yml +++ b/docs/_quarto.yml @@ -44,6 +44,7 @@ website: - guides/authoring/title-blocks.qmd - guides/authoring/dates.qmd - guides/authoring/scholarly-writing.qmd + - guides/authoring/document-language.qmd - guides/authoring/computations.qmd - guides/authoring/navigation.qmd - guides/authoring/extensions.qmd diff --git a/docs/guides/authoring/document-language.qmd b/docs/guides/authoring/document-language.qmd new file mode 100644 index 000000000..7a81187ef --- /dev/null +++ b/docs/guides/authoring/document-language.qmd @@ -0,0 +1,153 @@ +--- +title: "Document Language" +--- + +## Overview + +Quarto sometimes generates textual output in your rendered documents: cross-reference labels like "Figure" or "Table", callout titles like "Note" or "Warning", the table-of-contents title, and the labels in a document's title block. These strings are *localized* — they follow the language of your document, not the language of Quarto's own interface (which stays in English). + +## `lang` Option + +The `lang` document option identifies the main language of the document using [BCP 47](https://tools.ietf.org/html/bcp47) language tags (such as `en` or `en-GB`). For example, this document specifies French: + +``` yaml +--- +title: "Mon Document" +lang: fr +--- +``` + +This selects the French translations for generated text and sets the `lang` attribute of the rendered HTML document. The following languages currently ship with full translations: + +- English (`en`, used by default) +- Basque (`eu`) +- Bulgarian (`bg`) +- Catalan (`ca`) +- Chinese (`zh`; Traditional: `zh-TW`) +- Czech (`cs`) +- Danish (`da`) +- Dutch (`nl`) +- Finnish (`fi`) +- French (`fr`; Canadian: `fr-CA`) +- German (`de`; Swiss: `de-CH`) +- Greek (`el`) +- Hebrew (`he`) +- Icelandic (`is`) +- Indonesian (`id`) +- Italian (`it`) +- Japanese (`ja`) +- Korean (`ko`) +- Lithuanian (`lt`) +- Norwegian Bokmål (`nb`) +- Norwegian Nynorsk (`nn`) +- Polish (`pl`) +- Portuguese (`pt`; Brazilian: `pt-BR`) +- Russian (`ru`) +- Serbian, Latin script (`sr-Latn`) +- Slovak (`sk`) +- Slovenian (`sl`) +- Spanish (`es`) +- Swedish (`sv`) +- Turkish (`tr`) +- Ukrainian (`ua`) + +Regional variants fall back to their base language: with `lang: pt-BR`, Quarto first applies the Portuguese (`pt`) translations, then the Brazilian overrides on top. A region without its own translation file (say `es-MX`) simply uses the base language (`es`). + +`lang` can be set at the project level (in `_quarto.yml`) or per document; document settings win. + +## Alternate Language + +If you aren't happy with the generated text for a given part of a document, you can provide alternate values via the `language` key (at a project or document level). For example, to override the labels used within title blocks: + +``` yaml +--- +title: "My Document" +author: "Norah Jones" +date: 5/22/2022 +language: + title-block-author-single: "Writer" + title-block-published: "Updated" +--- +``` + +You can also provide these values in a standalone YAML file and reference it as follows: + +``` yaml +--- +title: "My Document" +language: custom.yml +--- +``` + +The file path is resolved relative to the document, then to the project root. All customizable keys are listed in Quarto's built-in [`_language.yml`](https://github.com/quarto-dev/q2/blob/main/resources/language/_language.yml) file. If you use a key Quarto doesn't recognize, the render emits a warning pointing at the key (the value is still kept, and remains usable from custom templates — see below). + +### Per-Language Alternates + +Alternate values can be restricted to a particular target language using subkeys of the `language` key. For example, to override the English and French versions of the "Published" caption: + +``` yaml +--- +title: "My Document" +date: 5/22/2022 +lang: fr +language: + en: + title-block-published: "Updated" + fr: + title-block-published: "Mis à jour" +--- +``` + +In this case "Mis à jour" is used, since `lang` is set to `fr`. Per-language subkeys also follow the BCP 47 fallback: a `fr:` subkey applies to `fr-CA` documents unless a more specific `fr-CA:` subkey is present. These language-restricted values can also live in a standalone YAML file: + +``` {.yaml filename="custom-language.yml"} +en: + title-block-published: "Updated" +fr: + title-block-published: "Mis à jour" +``` + +### Cross-Reference Titles and Prefixes + +Cross-reference labels follow the same mechanism. Keys of the form `crossref-{type}-title` control the caption prefix ("Figura 1: …"), and `crossref-{type}-prefix` controls the reference text ("see Figura 1"), where `{type}` is a built-in category (`fig`, `tbl`, `lst`, `sec`, `eq`), a theorem environment (`thm`, `lem`, `cor`, `prp`, `cnj`, `def`, `exm`, `exr`), or a custom cross-reference kind. When `crossref-{type}-prefix` is omitted it falls back to `crossref-{type}-title`. + +For example, to localize figure and table labels in a Spanish document: + +``` yaml +--- +title: "Mi Documento" +lang: es +language: + crossref-fig-title: "Figura" + crossref-tbl-title: "Tabla" + crossref-eq-prefix: "Ecuación" +--- +``` + +## Custom Translations + +To use a language Quarto doesn't ship a translation for: + +1. Make a copy of the default [`_language.yml`](https://github.com/quarto-dev/q2/blob/main/resources/language/_language.yml). + +2. Translate the values from the English defaults. + +3. Reference the file from your document or project: + + ``` yaml + --- + language: custom.yml + --- + ``` + +Additionally, if you place a `_language.yml` file in the root of your project alongside `_quarto.yml`, it is used automatically. Sibling files named `_language-{tag}.yml` (for example `_language-fr.yml`) provide per-language overrides that activate when `lang` matches. + +## Language Terms in Templates + +Every resolved term — including custom keys you define under `language` — is available to [custom templates](templates.qmd) under the `quarto.language` namespace: + +``` html +

$quarto.language.toc-title-document$

+``` + +The `quarto.language` metadata subtree is reserved: Quarto injects the resolved term table there during rendering. diff --git a/resources/language/README.md b/resources/language/README.md new file mode 100644 index 000000000..37286a6f8 --- /dev/null +++ b/resources/language/README.md @@ -0,0 +1,29 @@ +# Language term files (localization) + +Per-language translations of Quarto's document-visible terms (callout titles, +crossref titles/prefixes, TOC title, title-block labels, etc.). + +- `_language.yml` — English defaults; the authoritative catalog of term keys. +- `_language-.yml` — overrides for one BCP 47 tag. Region/script variants + (`_language-pt-BR.yml`, `_language-de-CH.yml`, `_language-sr-Latn.yml`) are + merged on top of their parent (`_language-pt.yml`, …) via the subtag walk in + `crates/quarto-core/src/language.rs`. + +These files are embedded into the `quarto-core` binary via `include_dir!` +(see `crates/quarto-core/src/language.rs`) and resolved at render time based +on the document's `lang` option and `language:` metadata overrides. + +## Provenance + +Copied from `quarto-cli` (`src/resources/language/`) at commit +`45caede32a0f987c4a377a952120cac6d624cb31` (v1.10.3-116-g45caede32) on +2026-07-17, per the external-sources policy (compile-time resources must live +in-repo, never referenced from `external-sources/`). + +To update: re-copy the files from a current `quarto-cli` checkout, update the +commit hash above, and run the catalog integrity test +(`cargo nextest run -p quarto-core -E 'test(language_catalog)'`). Key-level +compatibility with Quarto 1 is deliberate — do not rename keys. + +Design: `claude-notes/plans/2026-07-17-localization-i18n-design.md` +(braid strand bd-llhlzd7p). diff --git a/resources/language/_language-bg.yml b/resources/language/_language-bg.yml new file mode 100644 index 000000000..4175f4788 --- /dev/null +++ b/resources/language/_language-bg.yml @@ -0,0 +1,131 @@ +toc-title-document: "Съдържание" +toc-title-website: "На тази страница" + +related-formats-title: "Други формати" +related-notebooks-title: "Тетрадки" +source-notebooks-prefix: "Източник" +other-links-title: "Други връзки" +code-links-title: "Връзки към код" +launch-dev-container-title: "Стартиране на контейнер за разработка" +launch-binder-title: "Стартиране на Binder" + +article-notebook-label: "Статия - Тетрадка" +notebook-preview-download: "Изтегли тетрадка" +notebook-preview-download-src: "Изтегли източник" +notebook-preview-back: "Обратно към статията" +manuscript-meca-bundle: "MECA пакет" + +section-title-abstract: "Резюме" +section-title-appendices: "Приложения" +section-title-footnotes: "Бележки под линия" +section-title-references: "Референции" +section-title-reuse: "Повторна употреба" +section-title-copyright: "Авторски права" +section-title-citation: "Цитиране" + +appendix-attribution-cite-as: "За атрибуция, моля цитирайте това произведение като:" +appendix-attribution-bibtex: "Цитиране в BibTeX:" +appendix-view-license: "Преглед на лиценз" + +title-block-author-single: "Автор" +title-block-author-plural: "Автори" +title-block-affiliation-single: "Институция" +title-block-affiliation-plural: "Институции" +title-block-published: "Публикувано" +title-block-modified: "Променено" +title-block-keywords: "Ключови думи" + +callout-tip-title: "Съвет" +callout-note-title: "Бележка" +callout-warning-title: "Предупреждение" +callout-important-title: "Важно" +callout-caution-title: "Внимание" + +code-summary: "Код" + +code-tools-menu-caption: "Код" +code-tools-show-all-code: "Покажи целия код" +code-tools-hide-all-code: "Скрий целия код" +code-tools-view-source: "Преглед на източника" +code-tools-source-code: "Изходен код" + +tools-share: "Сподели" +tools-download: "Изтегли" + +code-line: "Ред" +code-lines: "Редове" + +copy-button-tooltip: "Копирай в клипборда" +copy-button-tooltip-success: "Копирано!" + +repo-action-links-edit: "Редактирай тази страница" +repo-action-links-source: "Преглед на източника" +repo-action-links-issue: "Докладвай проблем" + +back-to-top: "Обратно в началото" + +search-no-results-text: "Няма резултати" +search-matching-documents-text: "съвпадащи документи" +search-copy-link-title: "Копирай връзката към търсенето" +search-hide-matches-text: "Скрий допълнителните съвпадения" +search-more-match-text: "още едно съвпадение в този документ" +search-more-matches-text: "още съвпадения в този документ" +search-clear-button-title: "Изчисти" +search-text-placeholder: "" +search-detached-cancel-button-title: "Отказ" +search-submit-button-title: "Търси" +search-label: "Търсене" + +toggle-section: "Превключи секцията" +toggle-sidebar: "Превключи навигацията в страничната лента" +toggle-dark-mode: "Превключи на тъмен режим" +toggle-reader-mode: "Превключи на режим за четене" +toggle-navigation: "Превключи навигацията" + +crossref-fig-title: "Фигура" +crossref-tbl-title: "Таблица" +crossref-lst-title: "Изброяване" +crossref-thm-title: "Теорема" +crossref-lem-title: "Лема" +crossref-cor-title: "Следствие" +crossref-prp-title: "Предложение" +crossref-cnj-title: "Хипотеза" +crossref-def-title: "Дефиниция" +crossref-exm-title: "Пример" +crossref-exr-title: "Упражнение" +crossref-ch-prefix: "Глава" +crossref-apx-prefix: "Приложение" +crossref-sec-prefix: "Раздел" +crossref-eq-prefix: "Уравнение" +crossref-lof-title: "Списък на фигурите" +crossref-lot-title: "Списък на таблиците" +crossref-lol-title: "Списък на изброяванията" + +environment-proof-title: "Доказателство" +environment-remark-title: "Забележка" +environment-solution-title: "Решение" + +listing-page-order-by: "Подреди по" +listing-page-order-by-default: "По подразбиране" +listing-page-order-by-date-asc: "Най-старо" +listing-page-order-by-date-desc: "Най-ново" +listing-page-order-by-number-desc: "От високо към ниско" +listing-page-order-by-number-asc: "От ниско към високо" +listing-page-field-date: "Дата" +listing-page-field-title: "Заглавие" +listing-page-field-description: "Описание" +listing-page-field-author: "Автор" +listing-page-field-filename: "Име на файла" +listing-page-field-filemodified: "Променено" +listing-page-field-subtitle: "Подзаглавие" +listing-page-field-readingtime: "Време за четене" +listing-page-field-wordcount: "Брой думи" +listing-page-field-categories: "Категории" +listing-page-minutes-compact: "{0} мин" +listing-page-category-all: "Всички" +listing-page-no-matches: "Няма съвпадения" +listing-page-words: "{0} думи" +listing-page-filter: "Филтър" + +draft: "Чернова" + diff --git a/resources/language/_language-ca.yml b/resources/language/_language-ca.yml new file mode 100644 index 000000000..224203a36 --- /dev/null +++ b/resources/language/_language-ca.yml @@ -0,0 +1,127 @@ +toc-title-document: "Taula de continguts" +toc-title-website: "En aquesta pàgina" + +related-formats-title: "Altres formats" +related-notebooks-title: "Blocs de notes" +source-notebooks-prefix: "Font" +other-links-title: "Altres enllaços" +code-links-title: "Enllaços de codi" +launch-dev-container-title: "Llança Dev Container" +launch-binder-title: "Llança Binder" + +article-notebook-label: "Bloc de notes de l'article" +notebook-preview-download: "Descarrega el bloc de notes" +notebook-preview-download-src: "Descarrega el codi" +notebook-preview-back: "Torna a l'article" +manuscript-meca-bundle: "Arxiu MECA" + +section-title-abstract: "Resum" +section-title-appendices: "Apèndixs" +section-title-footnotes: "Notes a peu de pàgina" +section-title-references: "Referències" +section-title-reuse: "Reutilització" +section-title-copyright: "Drets d'autor" +section-title-citation: "Com citar" + +appendix-attribution-cite-as: "Per l'atribució, citeu aquest treball com:" +appendix-attribution-bibtex: "Citació en BibTeX:" +appendix-view-license: "Veure Llicència" + +title-block-author-single: "Autor/a" +title-block-author-plural: "Autors/es" +title-block-affiliation-single: "Afiliació" +title-block-affiliation-plural: "Afiliacions" +title-block-published: "Publicat" +title-block-modified: "Modificat" +title-block-keywords: "Paraules clau" + +callout-tip-title: "Consell" +callout-note-title: "Nota" +callout-warning-title: "Alerta" +callout-important-title: "Important" +callout-caution-title: "Precaució" + +code-summary: "Codi" + +code-tools-menu-caption: "Codi" +code-tools-show-all-code: "Mostra tot el codi" +code-tools-hide-all-code: "Amaga tot el codi" +code-tools-view-source: "Visualitza el codi" +code-tools-source-code: "Codi font" + +code-line: "Línia" +code-lines: "Línies" + +copy-button-tooltip: "Copia al porta-retalls" +copy-button-tooltip-success: "Copiat!" + +repo-action-links-edit: "Edita aquesta pàgina" +repo-action-links-source: "Mostra la font" +repo-action-links-issue: "Informa d'un problema" + +back-to-top: "Torna a dalt" + +search-no-results-text: "Cap resultat" +search-matching-documents-text: "documents que coincideixen" +search-copy-link-title: "Copia l'enllaç a la cerca" +search-hide-matches-text: "Amaga les coincidències addicionals" +search-more-match-text: "altra coincidència en aquest document" +search-more-matches-text: "altres coincidències en aquest document" +search-clear-button-title: "Neteja" +search-text-placeholder: "" +search-detached-cancel-button-title: "Cancel·la" +search-submit-button-title: "Envia" +search-label: "Cerca" + +toggle-section: "Commuta la secció" +toggle-sidebar: "Commuta la navegació de la barra lateral" +toggle-dark-mode: "Commuta el mode fosc" +toggle-reader-mode: "Commuta el mode de lectura" +toggle-navigation: "Commuta la navegació" + +crossref-fig-title: "Figura" +crossref-tbl-title: "Taula" +crossref-lst-title: "Llistat" +crossref-thm-title: "Teorema" +crossref-lem-title: "Lema" +crossref-cor-title: "Corol·lari" +crossref-prp-title: "Proposició" +crossref-cnj-title: "Conjectura" +crossref-def-title: "Definició" +crossref-exm-title: "Exemple" +crossref-exr-title: "Exercici" +crossref-ch-prefix: "Capítol" +crossref-apx-prefix: "Apèndix" +crossref-sec-prefix: "Secció" +crossref-eq-prefix: "Equació" +crossref-lof-title: "Llista de figures" +crossref-lot-title: "Llista de taules" +crossref-lol-title: "Llista de llistats" + +environment-proof-title: "Demostració" +environment-remark-title: "Observació" +environment-solution-title: "Solució" + +listing-page-order-by: "Ordena per" +listing-page-order-by-default: "Defecte" +listing-page-order-by-date-asc: "Més antic" +listing-page-order-by-date-desc: "Més nou" +listing-page-order-by-number-desc: "De major a menor" +listing-page-order-by-number-asc: "De menor a major" +listing-page-field-date: "Data" +listing-page-field-title: "Títol" +listing-page-field-description: "Descripció" +listing-page-field-author: "Autor/a" +listing-page-field-filename: "Nom de fitxer" +listing-page-field-filemodified: "Modificat" +listing-page-field-subtitle: "Subtítol" +listing-page-field-readingtime: "Temps de lectura" +listing-page-field-wordcount: "Recompte de paraules" +listing-page-field-categories: "Categories" +listing-page-minutes-compact: "{0} min" +listing-page-category-all: "Tot" +listing-page-no-matches: "Cap element coincident" +listing-page-words: "{0} paraules" +listing-page-filter: "Filtre" + +draft: "Esborrany" diff --git a/resources/language/_language-cs.yml b/resources/language/_language-cs.yml new file mode 100644 index 000000000..070d52193 --- /dev/null +++ b/resources/language/_language-cs.yml @@ -0,0 +1,127 @@ +toc-title-document: "Obsah" +toc-title-website: "Na této stránce" + +related-formats-title: "Jiné formáty" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "Zdroj" +other-links-title: "Další odkazy" +code-links-title: "Odkazy na kód" +launch-dev-container-title: "Spustit Dev Container" +launch-binder-title: "Spustit Binder" + +article-notebook-label: "Poznámkový blok článku" +notebook-preview-download: "Stáhnout poznámkový blok" +notebook-preview-download-src: "Stáhnout zdrojový kód" +notebook-preview-back: "Zpět na článek" +manuscript-meca-bundle: "Archiv MECA" + +section-title-abstract: "Abstrakt" +section-title-appendices: "Přílohy" +section-title-footnotes: "Poznámky pod čarou" +section-title-references: "Reference" +section-title-reuse: "Pravidla uživání" +section-title-copyright: "Autorská práva" +section-title-citation: "Citace" + +appendix-attribution-cite-as: "Tuto práci citujte jako:" +appendix-attribution-bibtex: "BibTeX citace:" +appendix-view-license: "Zobrazit Licenci" + +title-block-author-single: "Autor" +title-block-author-plural: "Autoři" +title-block-affiliation-single: "Afiliace" +title-block-affiliation-plural: "Afiliace" +title-block-published: "Publikováno" +title-block-modified: "Upraveno" +title-block-keywords: "Klíčová slova" + +callout-tip-title: "Tip" +callout-note-title: "Poznámka" +callout-warning-title: "Varování" +callout-important-title: "Důležité" +callout-caution-title: "Upozornění" + +code-summary: "Kód" + +code-line: "Řádek" +code-lines: "Řádky" + +code-tools-menu-caption: "Kód" +code-tools-show-all-code: "Zobrazit celý kód" +code-tools-hide-all-code: "Skrýt celý kód" +code-tools-view-source: "Zobrazit zdrojový kód" +code-tools-source-code: "Zdrojový kód" + +copy-button-tooltip: "Zkopírovat do schránky" +copy-button-tooltip-success: "Zkopírováno!" + +repo-action-links-edit: "Upravit stránku" +repo-action-links-source: "Zobrazit zdrojový kód" +repo-action-links-issue: "Nahlásit problém" + +back-to-top: "Zpět na začátek" + +search-no-results-text: "Žádný výsledek" +search-matching-documents-text: "Nalezené výsledky" +search-copy-link-title: "Zkopírovat odkaz pro vyhledávání" +search-hide-matches-text: "Skrýt další výsledky" +search-more-match-text: "další výsledek v tomto dokumentu" +search-more-matches-text: "dalších výsledků v tomto dokumentu" +search-clear-button-title: "Vymazat" +search-text-placeholder: "" +search-detached-cancel-button-title: "Zrušit" +search-submit-button-title: "Odeslat" +search-label: "Hledat" + +toggle-section: "Přepnout sekci" +toggle-sidebar: "Přepnout postranní panel" +toggle-dark-mode: "Přepnout tmavý režim" +toggle-reader-mode: "Přepnout režim čtečky" +toggle-navigation: "Přepnout navigaci" + +crossref-fig-title: "Obrázek" +crossref-tbl-title: "Tabulka" +crossref-lst-title: "Výpis" +crossref-thm-title: "Teorém" +crossref-lem-title: "Lemma" +crossref-cor-title: "Důsledek" +crossref-prp-title: "Tvrzení" +crossref-cnj-title: "Konjektura" +crossref-def-title: "Definice" +crossref-exm-title: "Příklad" +crossref-exr-title: "Cvičení" +crossref-ch-prefix: "Kapitola" +crossref-apx-prefix: "Příloha" +crossref-sec-prefix: "Sekce" +crossref-eq-prefix: "Rovnice" +crossref-lof-title: "Seznam obrázků" +crossref-lot-title: "Seznam tabulek" +crossref-lol-title: "Seznam výpisů" + +environment-proof-title: "Důkaz" +environment-remark-title: "Poznámka" +environment-solution-title: "Řešení" + +listing-page-order-by: "Seřadit podle" +listing-page-order-by-default: "Výchozí" +listing-page-order-by-date-asc: "Nejstarší" +listing-page-order-by-date-desc: "Nejnovější" +listing-page-order-by-number-desc: "Nejvyšší po nejnižší" +listing-page-order-by-number-asc: "Nejnižší po nejvyšší" +listing-page-field-date: "Datum" +listing-page-field-title: "Název" +listing-page-field-description: "Popis" +listing-page-field-author: "Autor" +listing-page-field-filename: "Název souboru" +listing-page-field-filemodified: "Upraveno" +listing-page-field-subtitle: "Podtitul" +listing-page-field-readingtime: "Doba čtení" +listing-page-field-categories: "Kategorie" +listing-page-minutes-compact: "{0} minut" +listing-page-category-all: "Vše" +listing-page-no-matches: "Žádné nalezené výsledky" +listing-page-field-wordcount: "Počet slov" +listing-page-words: "{0} slov" +listing-page-filter: "Filtr" + +draft: "Návrh" diff --git a/resources/language/_language-da.yml b/resources/language/_language-da.yml new file mode 100644 index 000000000..516515d40 --- /dev/null +++ b/resources/language/_language-da.yml @@ -0,0 +1,127 @@ +toc-title-document: "Indholdsfortegnelse" +toc-title-website: "På denne side" + +related-formats-title: "Andre formater" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "Kilde" +other-links-title: "Andre links" +code-links-title: "Kodelinks" +launch-dev-container-title: "Start Dev Container" +launch-binder-title: "Start Binder" + +article-notebook-label: "Artikel Notebook" +notebook-preview-download: "Download Notebook" +notebook-preview-download-src: "Download kildekode" +notebook-preview-back: "Tilbage til artikel" +manuscript-meca-bundle: "MECA Arkiv" + +section-title-abstract: "Resume" +section-title-appendices: "Bilag" +section-title-footnotes: "Fodnoter" +section-title-references: "Referencer" +section-title-reuse: "Genbrug" +section-title-copyright: "Ophavsret" +section-title-citation: "Citat" + +appendix-attribution-bibtex: "Henvis til dette arbejde som:" +appendix-attribution-cite-as: "BibTeX henvisning:" +appendix-view-license: "Vis Licens" + +title-block-author-single: "Forfatter" +title-block-author-plural: "Forfattere" +title-block-affiliation-single: "Tilknytning" +title-block-affiliation-plural: "Tilknytninger" +title-block-published: "Udgivet" +title-block-modified: "Ændret" +title-block-keywords: "Nøgleord" + +callout-tip-title: "Tip" +callout-note-title: "Note" +callout-warning-title: "Advarsel" +callout-important-title: "Vigtigt" +callout-caution-title: "Forsigtig" + +code-summary: "Kode" + +code-line: "Linje" +code-lines: "Linjer" + +code-tools-menu-caption: "Kode" +code-tools-show-all-code: "Vis al kode" +code-tools-hide-all-code: "Skjul al kode" +code-tools-view-source: "Vis kilde" +code-tools-source-code: "Kildekode" + +copy-button-tooltip: "Kopier til udklipsholder" +copy-button-tooltip-success: "Kopieret!" + +repo-action-links-edit: "Modificer denne side" +repo-action-links-source: "Vis kilde" +repo-action-links-issue: "Anmeld problem" + +back-to-top: "Tilbage til toppen" + +search-no-results-text: "Ingen resultater" +search-matching-documents-text: "Matchende dokumenter" +search-copy-link-title: "Kopier link for at søge" +search-hide-matches-text: "Skjul yderligere resultater" +search-more-match-text: "andet resultat i dette dokument" +search-more-matches-text: "andre resultater i dette dokument" +search-clear-button-title: "Ryd" +search-text-placeholder: "" +search-detached-cancel-button-title: "Fortryd" +search-submit-button-title: "Indsend" +search-label: "Søg" + +toggle-section: "Skift sektion" +toggle-sidebar: "Skift sidebjælke" +toggle-dark-mode: "Skift mørk tilstand" +toggle-reader-mode: "Skift læsetilstand" +toggle-navigation: "Skift navigation" + +crossref-fig-title: "Figur" +crossref-tbl-title: "Tabel" +crossref-lst-title: "Liste" +crossref-thm-title: "Sætning" +crossref-lem-title: "Hjælpesætning" +crossref-cor-title: "Følgesætning" +crossref-prp-title: "Erklæring" +crossref-cnj-title: "Formodning" +crossref-def-title: "Definition" +crossref-exm-title: "Eksempel" +crossref-exr-title: "Øvelse" +crossref-ch-prefix: "Kapitel" +crossref-apx-prefix: "Bilag" +crossref-sec-prefix: "Sektion" +crossref-eq-prefix: "Ligning" +crossref-lof-title: "Figuroversigt" +crossref-lot-title: "Tabeloversigt" +crossref-lol-title: "Listeoversigt" + +environment-proof-title: "Bevis" +environment-remark-title: "Bemærkning" +environment-solution-title: "Løsning" + +listing-page-order-by: "Sorter ved" +listing-page-order-by-default: "Standard" +listing-page-order-by-date-asc: "Ældste" +listing-page-order-by-date-desc: "Nyeste" +listing-page-order-by-number-desc: "Faldende" +listing-page-order-by-number-asc: "Stigende" +listing-page-field-date: "Dato" +listing-page-field-title: "Overskrift" +listing-page-field-description: "Beskrivelse" +listing-page-field-author: "Forfatter" +listing-page-field-filename: "Filnavn" +listing-page-field-filemodified: "Ændret" +listing-page-field-subtitle: "Underoverskrift" +listing-page-field-readingtime: "Læsetid" +listing-page-field-categories: "Kategorier" +listing-page-minutes-compact: "{0} min" +listing-page-category-all: "Alle" +listing-page-no-matches: "Ingen resultater" +listing-page-field-wordcount: "Ordtælling" +listing-page-words: "{0} ord" +listing-page-filter: "Filter" + +draft: "Udkast" diff --git a/resources/language/_language-de-CH.yml b/resources/language/_language-de-CH.yml new file mode 100644 index 000000000..0d64bbf93 --- /dev/null +++ b/resources/language/_language-de-CH.yml @@ -0,0 +1,127 @@ +toc-title-document: "Inhaltsverzeichnis" +toc-title-website: "Auf dieser Seite" + +related-formats-title: "Andere Formate" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "Quelle" +other-links-title: "Weitere Links" +code-links-title: "Code-Links" +launch-dev-container-title: "Dev Container starten" +launch-binder-title: "Binder starten" + +article-notebook-label: "Artikel-Notizbuch" +notebook-preview-download: "Notizbuch herunterladen" +notebook-preview-download-src: "Quellcode herunterladen" +notebook-preview-back: "Zurück zum Artikel" +manuscript-meca-bundle: "MECA-Archiv" + +section-title-abstract: "Zusammenfassung" +section-title-appendices: "Anhang" +section-title-footnotes: "Fussnoten" +section-title-references: "Literatur" +section-title-reuse: "Wiederverwendung" +section-title-copyright: "Urheberrechte" +section-title-citation: "Zitat" + +appendix-attribution-bibtex: "Mit BibTeX zitieren:" +appendix-attribution-cite-as: "Bitte zitieren Sie diese Arbeit als:" +appendix-view-license: "Lizenz anzeigen" + +title-block-author-single: "Autor:in" +title-block-author-plural: "Autor:innen" +title-block-affiliation-single: "Zugehörigkeit" +title-block-affiliation-plural: "Zugehörigkeiten" +title-block-published: "Veröffentlichungsdatum" +title-block-modified: "Geändert" +title-block-keywords: "Schlüsselwörter" + +callout-tip-title: "Tipp" +callout-note-title: "Hinweis" +callout-warning-title: "Warnung" +callout-important-title: "Wichtig" +callout-caution-title: "Vorsicht" + +code-summary: "Code" + +code-line: "Zeile" +code-lines: "Zeilen" + +code-tools-menu-caption: "Code" +code-tools-show-all-code: "Gesamten Code zeigen" +code-tools-hide-all-code: "Gesamten Code verbergen" +code-tools-view-source: "Quellcode anzeigen" +code-tools-source-code: "Quellcode" + +copy-button-tooltip: "In die Zwischenablage kopieren" +copy-button-tooltip-success: "Kopiert" + +repo-action-links-edit: "Seite editieren" +repo-action-links-source: "Quellcode anzeigen" +repo-action-links-issue: "Problem melden" + +back-to-top: "Zurück nach oben" + +search-no-results-text: "Keine Treffer" +search-matching-documents-text: "Treffer" +search-copy-link-title: "Link in die Suche kopieren" +search-hide-matches-text: "Zusätzliche Treffer verbergen" +search-more-match-text: "weitere Treffer in diesem Dokument" +search-more-matches-text: "weitere Treffer in diesem Dokument" +search-clear-button-title: "Zurücksetzen" +search-text-placeholder: "" +search-detached-cancel-button-title: "Abbrechen" +search-submit-button-title: "Abschicken" +search-label: "Suchen" + +toggle-section: "Abschnitt umschalten" +toggle-sidebar: "Seitenleiste umschalten" +toggle-dark-mode: "Dunkelmodus umschalten" +toggle-reader-mode: "Lesemodus umschalten" +toggle-navigation: "Navigation umschalten" + +crossref-fig-title: "Abbildung" +crossref-tbl-title: "Tabelle" +crossref-lst-title: "Listing" +crossref-thm-title: "Theorem" +crossref-lem-title: "Lemma" +crossref-cor-title: "Korollar" +crossref-prp-title: "Aussage" +crossref-cnj-title: "Annahme" +crossref-def-title: "Definition" +crossref-exm-title: "Beispiel" +crossref-exr-title: "Übungsaufgabe" +crossref-ch-prefix: "Kapitel" +crossref-apx-prefix: "Anhang" +crossref-sec-prefix: "Kapitel" +crossref-eq-prefix: "Gleichung" +crossref-lof-title: "Abbildungsverzeichnis" +crossref-lot-title: "Tabellenverzeichnis" +crossref-lol-title: "Listingverzeichnis" + +environment-proof-title: "Beweis" +environment-remark-title: "Anmerkung" +environment-solution-title: "Lösung" + +listing-page-order-by: "Sortieren nach" +listing-page-order-by-default: "Voreinstellung" +listing-page-order-by-date-asc: "Datum (aufsteigend)" +listing-page-order-by-date-desc: "Neueste" +listing-page-order-by-number-desc: "Absteigend" +listing-page-order-by-number-asc: "Aufsteigend" +listing-page-field-date: "Datum" +listing-page-field-title: "Titel" +listing-page-field-description: "Beschreibung" +listing-page-field-author: "Autor:in" +listing-page-field-filename: "Dateiname" +listing-page-field-filemodified: "Geändert" +listing-page-field-subtitle: "Untertitel" +listing-page-field-readingtime: "Lesezeit" +listing-page-field-categories: "Kategorien" +listing-page-minutes-compact: "{0} min" +listing-page-category-all: "alle" +listing-page-no-matches: "Keine Treffer" +listing-page-field-wordcount: "Wortanzahl" +listing-page-words: "{0} Wörter" +listing-page-filter: "Filter" + +draft: "Entwurf" diff --git a/resources/language/_language-de.yml b/resources/language/_language-de.yml new file mode 100644 index 000000000..ebb8fa4e6 --- /dev/null +++ b/resources/language/_language-de.yml @@ -0,0 +1,127 @@ +toc-title-document: "Inhaltsverzeichnis" +toc-title-website: "Auf dieser Seite" + +related-formats-title: "Andere Formate" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "Quelle" +other-links-title: "Weitere Links" +code-links-title: "Code-Links" +launch-dev-container-title: "Dev Container starten" +launch-binder-title: "Binder starten" + +article-notebook-label: "Artikel-Notizbuch" +notebook-preview-download: "Notizbuch herunterladen" +notebook-preview-download-src: "Quellcode herunterladen" +notebook-preview-back: "Zurück zum Artikel" +manuscript-meca-bundle: "MECA-Archiv" + +section-title-abstract: "Zusammenfassung" +section-title-appendices: "Anhang" +section-title-footnotes: "Fußnoten" +section-title-references: "Literatur" +section-title-reuse: "Wiederverwendung" +section-title-copyright: "Urheberrechte" +section-title-citation: "Zitat" + +appendix-attribution-bibtex: "Mit BibTeX zitieren:" +appendix-attribution-cite-as: "Bitte zitieren Sie diese Arbeit als:" +appendix-view-license: "Lizenz Anzeigen" + +title-block-author-single: "Autor:in" +title-block-author-plural: "Autor:innen" +title-block-affiliation-single: "Zugehörigkeit" +title-block-affiliation-plural: "Zugehörigkeiten" +title-block-published: "Veröffentlichungsdatum" +title-block-modified: "Geändert" +title-block-keywords: "Schlüsselwörter" + +callout-tip-title: "Tipp" +callout-note-title: "Hinweis" +callout-warning-title: "Warnung" +callout-important-title: "Wichtig" +callout-caution-title: "Vorsicht" + +code-summary: "Code" + +code-line: "Zeile" +code-lines: "Zeilen" + +code-tools-menu-caption: "Code" +code-tools-show-all-code: "Gesamten Code zeigen" +code-tools-hide-all-code: "Gesamten Code verbergen" +code-tools-view-source: "Quellcode anzeigen" +code-tools-source-code: "Quellcode" + +copy-button-tooltip: "In die Zwischenablage kopieren" +copy-button-tooltip-success: "Kopiert" + +repo-action-links-edit: "Seite editieren" +repo-action-links-source: "Quellcode anzeigen" +repo-action-links-issue: "Problem melden" + +back-to-top: "Zurück nach oben" + +search-no-results-text: "Keine Treffer" +search-matching-documents-text: "Treffer" +search-copy-link-title: "Link in die Suche kopieren" +search-hide-matches-text: "Zusätzliche Treffer verbergen" +search-more-match-text: "weitere Treffer in diesem Dokument" +search-more-matches-text: "weitere Treffer in diesem Dokument" +search-clear-button-title: "Zurücksetzen" +search-text-placeholder: "" +search-detached-cancel-button-title: "Abbrechen" +search-submit-button-title: "Abschicken" +search-label: "Suchen" + +toggle-section: "Abschnitt umschalten" +toggle-sidebar: "Seitenleiste umschalten" +toggle-dark-mode: "Dunkelmodus umschalten" +toggle-reader-mode: "Lesemodus umschalten" +toggle-navigation: "Navigation umschalten" + +crossref-fig-title: "Abbildung" +crossref-tbl-title: "Tabelle" +crossref-lst-title: "Listing" +crossref-thm-title: "Theorem" +crossref-lem-title: "Lemma" +crossref-cor-title: "Korollar" +crossref-prp-title: "Aussage" +crossref-cnj-title: "Annahme" +crossref-def-title: "Definition" +crossref-exm-title: "Beispiel" +crossref-exr-title: "Übungsaufgabe" +crossref-ch-prefix: "Kapitel" +crossref-apx-prefix: "Anhang" +crossref-sec-prefix: "Kapitel" +crossref-eq-prefix: "Gleichung" +crossref-lof-title: "Abbildungsverzeichnis" +crossref-lot-title: "Tabellenverzeichnis" +crossref-lol-title: "Listingverzeichnis" + +environment-proof-title: "Beweis" +environment-remark-title: "Anmerkung" +environment-solution-title: "Lösung" + +listing-page-order-by: "Sortieren nach" +listing-page-order-by-default: "Voreinstellung" +listing-page-order-by-date-asc: "Datum (aufsteigend)" +listing-page-order-by-date-desc: "Neueste" +listing-page-order-by-number-desc: "Absteigend" +listing-page-order-by-number-asc: "Aufsteigend" +listing-page-field-date: "Datum" +listing-page-field-title: "Titel" +listing-page-field-description: "Beschreibung" +listing-page-field-author: "Autor:in" +listing-page-field-filename: "Dateiname" +listing-page-field-filemodified: "Geändert" +listing-page-field-subtitle: "Untertitel" +listing-page-field-readingtime: "Lesezeit" +listing-page-field-categories: "Kategorien" +listing-page-minutes-compact: "{0} min" +listing-page-category-all: "alle" +listing-page-no-matches: "Keine Treffer" +listing-page-field-wordcount: "Wortanzahl" +listing-page-words: "{0} Wörter" +listing-page-filter: "Filter" + +draft: "Entwurf" diff --git a/resources/language/_language-el.yml b/resources/language/_language-el.yml new file mode 100644 index 000000000..dabdf4a5c --- /dev/null +++ b/resources/language/_language-el.yml @@ -0,0 +1,127 @@ +toc-title-document: "Πίνακας περιεχομένων" +toc-title-website: "Σε αυτήν τη σελίδα" + +related-formats-title: "Άλλες μορφές" +related-notebooks-title: "Σημειωματάρια" +source-notebooks-prefix: "Πηγή" +other-links-title: "Άλλοι Σύνδεσμοι" +code-links-title: "Σύνδεσμοι κώδικα" +launch-dev-container-title: "Εκκίνηση Dev Container" +launch-binder-title: "Εκκίνηση Binder" + +article-notebook-label: "Σημειωματάριο Άρθρου" +notebook-preview-download: "Λήψη Σημειωματαρίου" +notebook-preview-download-src: "Λήψη πηγαίου κώδικα" +notebook-preview-back: "Πίσω στο Άρθρο" +manuscript-meca-bundle: "Αρχείο MECA" + +section-title-abstract: "Περίληψη" +section-title-appendices: "Παραρτήματα" +section-title-footnotes: "Υποσημειώσεις" +section-title-references: "Αναφορές" +section-title-reuse: "Επαναχρησιμοποίηση" +section-title-copyright: "Πνευματικά δικαιώματα" +section-title-citation: "Αναφορά" +title-block-keywords: "Λέξεις-κλειδιά" + +appendix-attribution-cite-as: "Για απόδοση ευγνωμοσύνης, παρακαλούμε αναφερθείτε σε αυτό το έργο ως:" +appendix-attribution-bibtex: "Αναφορά BibTeX:" +appendix-view-license: "Προβολή Άδειας" + +title-block-author-single: "Συγγραφέας" +title-block-author-plural: "Συγγραφείς" +title-block-affiliation-single: "Συνδρομή" +title-block-affiliation-plural: "Συνδρομές" +title-block-published: "Δημοσιευμένο" +title-block-modified: "Τροποποιημένο" + +callout-tip-title: "Συμβουλή" +callout-note-title: "Σημείωση" +callout-warning-title: "Προειδοποίηση" +callout-important-title: "Σημαντικό" +callout-caution-title: "Προσοχή" + +code-summary: "Κώδικας" + +code-tools-menu-caption: "Κώδικας" +code-tools-show-all-code: "Εμφάνιση όλου του κώδικα" +code-tools-hide-all-code: "Απόκρυψη όλου του κώδικα" +code-tools-view-source: "Προβολή πηγαίου κώδικα" +code-tools-source-code: "Πηγαίος κώδικας" + +code-line: "Γραμμή" +code-lines: "Γραμμές" + +copy-button-tooltip: "Αντιγραφή στο πρόχειρο" +copy-button-tooltip-success: "Αντιγράφηκε!" + +repo-action-links-edit: "Επεξεργασία αυτής της σελίδας" +repo-action-links-source: "Προβολή πηγής" +repo-action-links-issue: "Αναφορά προβλήματος" + +back-to-top: "Επιστροφή στην κορυφή" + +search-no-results-text: "Δεν βρέθηκαν αποτελέσματα" +search-matching-documents-text: "ταιριάζοντα έγγραφα" +search-copy-link-title: "Αντιγραφή συνδέσμου αναζήτησης" +search-hide-matches-text: "Απόκρυψη επιπλέον αντιστοιχιών" +search-more-match-text: "επιπλέον αντιστοιχία σε αυτό το έγγραφο" +search-more-matches-text: "επιπλέον αντιστοιχίες σε αυτό το έγγραφο" +search-clear-button-title: "Καθαρισμός" +search-text-placeholder: "" +search-detached-cancel-button-title: "Ακύρωση" +search-submit-button-title: "Υποβολή" +search-label: "Αναζήτηση" + +toggle-section: "Εναλλαγή ενότητας" +toggle-sidebar: "Εναλλαγή πλαϊνής γραμμής πλοήγησης" +toggle-dark-mode: "Εναλλαγή σκοτεινού θέματος" +toggle-reader-mode: "Εναλλαγή λειτουργίας ανάγνωσης" +toggle-navigation: "Εναλλαγή πλοήγησης" + +crossref-fig-title: "Σχήμα" +crossref-tbl-title: "Πίνακας" +crossref-lst-title: "Κατάλογος" +crossref-thm-title: "Θεώρημα" +crossref-lem-title: "Λήμμα" +crossref-cor-title: "Πόρισμα" +crossref-prp-title: "Πρόταση" +crossref-cnj-title: "Υπόθεση" +crossref-def-title: "Ορισμός" +crossref-exm-title: "Παράδειγμα" +crossref-exr-title: "Άσκηση" +crossref-ch-prefix: "Κεφάλαιο" +crossref-apx-prefix: "Παράρτημα" +crossref-sec-prefix: "Ενότητα" +crossref-eq-prefix: "Εξίσωση" +crossref-lof-title: "Λίστα Σχημάτων" +crossref-lot-title: "Λίστα Πινάκων" +crossref-lol-title: "Λίστα Καταλόγων" + +environment-proof-title: "Απόδειξη" +environment-remark-title: "Παρατήρηση" +environment-solution-title: "Λύση" + +listing-page-order-by: "Ταξινόμηση κατά" +listing-page-order-by-default: "Προεπιλογή" +listing-page-order-by-date-asc: "Παλαιότερο" +listing-page-order-by-date-desc: "Νεότερο" +listing-page-order-by-number-desc: "Υψηλό προς Χαμηλό" +listing-page-order-by-number-asc: "Χαμηλό προς Υψηλό" +listing-page-field-date: "Ημερομηνία" +listing-page-field-title: "Τίτλος" +listing-page-field-description: "Περιγραφή" +listing-page-field-author: "Συγγραφέας" +listing-page-field-filename: "Όνομα αρχείου" +listing-page-field-filemodified: "Τροποποιήθηκε" +listing-page-field-subtitle: "Υπότιτλος" +listing-page-field-readingtime: "Χρόνος ανάγνωσης" +listing-page-field-categories: "Κατηγορίες" +listing-page-minutes-compact: "{0} λεπτά" +listing-page-category-all: "Όλα" +listing-page-no-matches: "Δεν υπάρχουν αντιστοιχίες" +listing-page-field-wordcount: "Μέτρηση Λέξεων" +listing-page-words: "{0} λέξεις" +listing-page-filter: "Φίλτρο" + +draft: "Σχέδιο" diff --git a/resources/language/_language-es.yml b/resources/language/_language-es.yml new file mode 100644 index 000000000..f7856d17e --- /dev/null +++ b/resources/language/_language-es.yml @@ -0,0 +1,130 @@ +toc-title-document: "Tabla de contenidos" +toc-title-website: "En esta página" + +related-formats-title: "Otros formatos" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "Fuente" +other-links-title: "Otros Enlaces" +code-links-title: "Enlaces de código" +launch-dev-container-title: "Iniciar Dev Container" +launch-binder-title: "Iniciar Binder" + +article-notebook-label: "Cuaderno de Artículo" +notebook-preview-download: "Descargar Cuaderno" +notebook-preview-download-src: "Descargar código fuente" +notebook-preview-back: "Volver al Artículo" +manuscript-meca-bundle: "Archivo MECA" + +section-title-abstract: "Resumen" +section-title-appendices: "Apéndices" +section-title-footnotes: "Notas" +section-title-references: "Referencias" +section-title-reuse: "Reutilización" +section-title-copyright: "Derechos de autor" +section-title-citation: "Cómo citar" + +appendix-attribution-bibtex: "BibTeX" +appendix-attribution-cite-as: "Por favor, cita este trabajo como:" +appendix-view-license: "Ver Licencia" + +title-block-author-single: "Autor/a" +title-block-author-plural: "Autores/as" +title-block-affiliation-single: "Afiliación" +title-block-affiliation-plural: "Afiliaciones" +title-block-published: "Fecha de publicación" +title-block-modified: "Fecha de última modificación" +title-block-keywords: "Palabras clave" + +callout-tip-title: "Tip" +callout-note-title: "Nota" +callout-warning-title: "Advertencia" +callout-important-title: "Importante" +callout-caution-title: "Precaución" + +code-summary: "Código" + +code-line: "Línea" +code-lines: "Líneas" + +code-tools-menu-caption: "Código" +code-tools-show-all-code: "Mostrar todo el código" +code-tools-hide-all-code: "Ocultar todo el código" +code-tools-view-source: "Ver el código fuente" +code-tools-source-code: "Ejecutar el código" + +tools-share: "Compartir" +tools-download: "Descargar" + +copy-button-tooltip: "Copiar al portapapeles" +copy-button-tooltip-success: "Copiado" + +repo-action-links-edit: "Editar esta página" +repo-action-links-source: "Ver el código" +repo-action-links-issue: "Informar sobre problema" + +back-to-top: "Volver arriba" + +search-no-results-text: "No se han encontrado resultados" +search-matching-documents-text: "documentos encontrados" +search-copy-link-title: "Copiar el enlace en la búsqueda" +search-hide-matches-text: "Ocultar resultados adicionales" +search-more-match-text: "resultado adicional en este documento" +search-more-matches-text: "resultados adicionales en este documento" +search-clear-button-title: "Borrar" +search-text-placeholder: "" +search-detached-cancel-button-title: "Cancelar" +search-submit-button-title: "Enviar" +search-label: "Buscar" + +toggle-section: "Alternar sección" +toggle-sidebar: "Alternar barra lateral" +toggle-dark-mode: "Alternar modo oscuro" +toggle-reader-mode: "Alternar modo lector" +toggle-navigation: "Navegación de palanca" + +crossref-fig-title: "Figura" +crossref-tbl-title: "Tabla" +crossref-lst-title: "Listado" +crossref-thm-title: "Teorema" +crossref-lem-title: "Lema" +crossref-cor-title: "Corolario" +crossref-prp-title: "Proposición" +crossref-cnj-title: "Conjetura" +crossref-def-title: "Definición" +crossref-exm-title: "Ejemplo" +crossref-exr-title: "Ejercicio" +crossref-ch-prefix: "Capítulo" +crossref-apx-prefix: "Apéndice" +crossref-sec-prefix: "Sección" +crossref-eq-prefix: "Ecuación" +crossref-lof-title: "Listado de Figuras" +crossref-lot-title: "Listado de Tablas" +crossref-lol-title: "Listado de Listados" + +environment-proof-title: "Demostración" +environment-remark-title: "Observación" +environment-solution-title: "Solución" + +listing-page-order-by: "Ordenar por" +listing-page-order-by-default: "Por defecto" +listing-page-order-by-date-asc: "Más antiguo" +listing-page-order-by-date-desc: "Más reciente" +listing-page-order-by-number-desc: "De mayor a menor" +listing-page-order-by-number-asc: "De menor a mayor" +listing-page-field-date: "Fecha" +listing-page-field-title: "Título" +listing-page-field-description: "Descripción" +listing-page-field-author: "Autor/a" +listing-page-field-filename: "Nombre del archivo" +listing-page-field-filemodified: "Última modificación" +listing-page-field-subtitle: "Subtítulo" +listing-page-field-readingtime: "Tiempo de lectura" +listing-page-field-categories: "Categorías" +listing-page-minutes-compact: "{0} minutos" +listing-page-category-all: "Todas" +listing-page-no-matches: "No hay resultados" +listing-page-field-wordcount: "Conteo de Palabras" +listing-page-words: "{0} palabras" +listing-page-filter: "Filtro" + +draft: "Borrador" diff --git a/resources/language/_language-eu.yml b/resources/language/_language-eu.yml new file mode 100644 index 000000000..fbecdb003 --- /dev/null +++ b/resources/language/_language-eu.yml @@ -0,0 +1,130 @@ +toc-title-document: "Aurkibidea" +toc-title-website: "Orri honetan" + +related-formats-title: "Beste Formatu Batzuk" +related-notebooks-title: "Koadernoak" +source-notebooks-prefix: "Iturburu-kodea" +other-links-title: "Beste Esteka Batzuk" +code-links-title: "Kode-estekak" +launch-dev-container-title: "Abiarazi Dev Edukiontzia" +launch-binder-title: "Abiarazi Binder" + +article-notebook-label: "Artikulu-Koadernoa" +notebook-preview-download: "Deskargatu Koadernoa" +notebook-preview-download-src: "Deskargatu Iturburu-kodea" +notebook-preview-back: "Artikulura Itzuli" +manuscript-meca-bundle: "MECA Fitxategi Sorta" + +section-title-abstract: "Laburpena" +section-title-appendices: "Eranskinak" +section-title-footnotes: "Oin-oharrak" +section-title-references: "Erreferentziak" +section-title-reuse: "Berrerabili" +section-title-copyright: "Copyright" +section-title-citation: "Aipamena" + +appendix-attribution-cite-as: "Mesedez, aipa ezazu lan hau hurrengo eran:" +appendix-attribution-bibtex: "BibTeX Aipamenak:" +appendix-view-license: "Ikusi Lizentzia" + +title-block-author-single: "Egilea" +title-block-author-plural: "Egileak" +title-block-affiliation-single: "Afiliazioa" +title-block-affiliation-plural: "Afiliazioak" +title-block-published: "Argitaratua" +title-block-modified: "Aldatua" +title-block-keywords: "Gako-hitzak" + +callout-tip-title: "Ahoulkua" +callout-note-title: "Oharra" +callout-warning-title: "Abisua" +callout-important-title: "Garrantzitsua" +callout-caution-title: "Kontuz" + +code-summary: "Kodea" + +code-tools-menu-caption: "Kodea" +code-tools-show-all-code: "Erakutsi Kode Guztia" +code-tools-hide-all-code: "Ezkutatu Kode Guztia" +code-tools-view-source: "Ikusi Iturburu-kodea" +code-tools-source-code: "Iturburu-kodea" + +tools-share: "Partekatu" +tools-download: "Deskargatu" + +code-line: "Lerroa" +code-lines: "Lerroak" + +copy-button-tooltip: "Kopiatu Arbelean" +copy-button-tooltip-success: "Kopiatuta!" + +repo-action-links-edit: "Orri hau editatu" +repo-action-links-source: "Ikusi iturburu-kodea" +repo-action-links-issue: "Arazo baten berri eman" + +back-to-top: "Itzuli gora" + +search-no-results-text: "Ez dago emaitzarik" +search-matching-documents-text: "bilatutako dokumentuak" +search-copy-link-title: "Kopiatu esteka bilatzeko" +search-hide-matches-text: "Ezkutatu gainontzeko emaitzak" +search-more-match-text: "emaitza gehigarria dokumentu honetan" +search-more-matches-text: "emaitza gehigarriak dokumentu honetan" +search-clear-button-title: "Garbitu" +search-text-placeholder: "" +search-detached-cancel-button-title: "Utzi" +search-submit-button-title: "Bidali" +search-label: "Bilatu" + +toggle-section: "Aldatu atala" +toggle-sidebar: "Aldatu alboko barraren nabigazioa" +toggle-dark-mode: "Aldatu modu iluna" +toggle-reader-mode: "Aldatu irakurle modua" +toggle-navigation: "Aldatu nabigazioa" + +crossref-fig-title: "Irudia" +crossref-tbl-title: "Taula" +crossref-lst-title: "Zerrendatua" +crossref-thm-title: "Teorema" +crossref-lem-title: "Lema" +crossref-cor-title: "Korolarioa" +crossref-prp-title: "Proposizioa" +crossref-cnj-title: "Aierua" +crossref-def-title: "Definizioa" +crossref-exm-title: "Adibidea" +crossref-exr-title: "Ariketa" +crossref-ch-prefix: "Kapitulua" # It is a postfix +crossref-apx-prefix: "Eranskina" # It is a postfix +crossref-sec-prefix: "Atala" # It is a postfix +crossref-eq-prefix: "Ekuazioa" # It is a postfix +crossref-lof-title: "Irudien zerrenda" +crossref-lot-title: "Taulen zerrenda" +crossref-lol-title: "Zerrendatuen zerrenda" + +environment-proof-title: "Proba" +environment-remark-title: "Oharra" +environment-solution-title: "Emaitza" + +listing-page-order-by: "Ordenatu honen arabera" +listing-page-order-by-default: "Lehenetsia" +listing-page-order-by-date-asc: "Zaharrena" +listing-page-order-by-date-desc: "Berriena" +listing-page-order-by-number-desc: "Goitik Behera" +listing-page-order-by-number-asc: "Behetik Gora" +listing-page-field-date: "Data" +listing-page-field-title: "Izenburua" +listing-page-field-description: "Deskribapena" +listing-page-field-author: "Egileak" +listing-page-field-filename: "Fitxategiaren izena" +listing-page-field-filemodified: "Aldatuta" +listing-page-field-subtitle: "Azpitituloa" +listing-page-field-readingtime: "Irakurtzeko denbora" +listing-page-field-wordcount: "Hitz Kontaketa" +listing-page-field-categories: "Kategoriak" +listing-page-minutes-compact: "{0} min" +listing-page-category-all: "Denak" +listing-page-no-matches: "Bat ez datozenak" +listing-page-words: "{0} hitz" +listing-page-filter: "Iragazkia" + +draft: "Zirriborroa" diff --git a/resources/language/_language-fi.yml b/resources/language/_language-fi.yml new file mode 100644 index 000000000..750624963 --- /dev/null +++ b/resources/language/_language-fi.yml @@ -0,0 +1,127 @@ +toc-title-document: "Sisällysluettelo" +toc-title-website: "Tällä sivulla" + +related-formats-title: "Muut muodot" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "Lähde" +other-links-title: "Muut linkit" +code-links-title: "Koodilinkit" +launch-dev-container-title: "Käynnistä Dev Container" +launch-binder-title: "Käynnistä Binder" + +article-notebook-label: "Artikkelin muistiinpanovihko" +notebook-preview-download: "Lataa muistiinpanovihko" +notebook-preview-download-src: "Lataa lähdekoodi" +notebook-preview-back: "Takaisin artikkeliin" +manuscript-meca-bundle: "MECA-arkisto" + +section-title-abstract: "Tiivistelmä" +section-title-appendices: "Liitteet" +section-title-footnotes: "Alaviitteet" +section-title-references: "Lähteet" +section-title-reuse: "Uudelleenkäyttö" +section-title-copyright: "Tekijänoikeus" +section-title-citation: "Viittaus" + +appendix-attribution-cite-as: "Viitatkaa tähän teokseen seuraavasti:" +appendix-attribution-bibtex: "BibTeX-viittaus:" +appendix-view-license: "Näytä Lisenssi" + +title-block-author-single: "Tekijä" +title-block-author-plural: "Tekijät" +title-block-affiliation-single: "Affiliaatio" +title-block-affiliation-plural: "Affiliaatiot" +title-block-published: "Julkaistu" +title-block-modified: "Muokattu" +title-block-keywords: "Avainsanat" + +callout-tip-title: "Vihje" +callout-note-title: "Huomautus" +callout-warning-title: "Varoitus" +callout-important-title: "Tärkeää" +callout-caution-title: "Vaara" + +code-summary: "Koodi" + +code-line: "Linja" +code-lines: "Linjat" + +code-tools-menu-caption: "Koodi" +code-tools-show-all-code: "Näytä kaikki koodi" +code-tools-hide-all-code: "Piilota kaikki koodi" +code-tools-view-source: "Näytä lähdekoodi" +code-tools-source-code: "Lähdekoodi" + +copy-button-tooltip: "Kopioi leikepöydälle" +copy-button-tooltip-success: "Kopioitu!" + +repo-action-links-edit: "Muokkaa sivua" +repo-action-links-source: "Näytä lähdekoodi" +repo-action-links-issue: "Ilmoita ongelmasta" + +back-to-top: "Takaisin alkuun" + +search-no-results-text: "Ei tuloksia" +search-matching-documents-text: "tulokset" +search-copy-link-title: "Kopioi linkki hakuun" +search-hide-matches-text: "Piilota loput tulokset" +search-more-match-text: "tulos tässä dokumentissa" +search-more-matches-text: "tulosta tässä dokumentissa" +search-clear-button-title: "Tyhjennä" +search-text-placeholder: "" +search-detached-cancel-button-title: "Peruuta" +search-submit-button-title: "Lähetä" +search-label: "Hae" + +toggle-section: "Vaihda osio" +toggle-sidebar: "Vaihda sivupalkki" +toggle-dark-mode: "Tumma tila päälle/pois" +toggle-reader-mode: "Vaihda lukijatilaa" +toggle-navigation: "Vaihda navigointi" + +crossref-fig-title: "Kuva" +crossref-tbl-title: "Taulukko" +crossref-lst-title: "Listaus" +crossref-thm-title: "Lause" +crossref-lem-title: "Apulause" +crossref-cor-title: "Korollaari" +crossref-prp-title: "Väittämä" +crossref-cnj-title: "Konjektuuri" +crossref-def-title: "Määritelmä" +crossref-exm-title: "Esimerkki" +crossref-exr-title: "Harjoitus" +crossref-ch-prefix: "Luku" +crossref-sec-prefix: "Alaluku" +crossref-eq-prefix: "Yhtälö" +crossref-lof-title: "Kuvien luettelo" +crossref-lot-title: "Taulukoiden luettelo" +crossref-lol-title: "Listausten luettelo" +crossref-apx-prefix: "Liite" + +environment-proof-title: "Todistus" +environment-remark-title: "Huomautus" +environment-solution-title: "Ratkaisu" + +listing-page-order-by: "Järjestys:" +listing-page-order-by-default: "Oletusarvo" +listing-page-order-by-date-asc: "Vanhin" +listing-page-order-by-date-desc: "Uusin" +listing-page-order-by-number-desc: "Laskeva" +listing-page-order-by-number-asc: "Nouseva" +listing-page-field-date: "Päiväys" +listing-page-field-title: "Otsikko" +listing-page-field-description: "Kuvaus" +listing-page-field-author: "Tekijä" +listing-page-field-filename: "Tiedostonimi" +listing-page-field-filemodified: "Muokattu" +listing-page-field-subtitle: "Alaotsikko" +listing-page-field-readingtime: "Lukuaika" +listing-page-field-categories: "Luokat" +listing-page-minutes-compact: "{0} min" +listing-page-category-all: "Kaikki" +listing-page-no-matches: "Ei hakutuloksia" +listing-page-field-wordcount: "Sanamäärä" +listing-page-words: "{0} sanaa" +listing-page-filter: "Suodatin" + +draft: "Luonnos" diff --git a/resources/language/_language-fr-CA.yml b/resources/language/_language-fr-CA.yml new file mode 100644 index 000000000..d2b1d149a --- /dev/null +++ b/resources/language/_language-fr-CA.yml @@ -0,0 +1,3 @@ +title-block-author-single: "Auteur(-trice)" +title-block-author-plural: "Auteures(-trices)" +listing-page-field-author: "Auteur(-trice)" diff --git a/resources/language/_language-fr.yml b/resources/language/_language-fr.yml new file mode 100644 index 000000000..f6fac35a4 --- /dev/null +++ b/resources/language/_language-fr.yml @@ -0,0 +1,127 @@ +toc-title-document: "Table des matières" +toc-title-website: "Sur cette page" + +related-formats-title: "Autres formats" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "La source" +other-links-title: "Autres liens" +code-links-title: "Liens de code" +launch-dev-container-title: "Lancer le Dev Container" +launch-binder-title: "Lancer le Binder" + +article-notebook-label: "Cahier d'articles" +notebook-preview-download: "Télécharger le cahier" +notebook-preview-download-src: "Télécharger le code source" +notebook-preview-back: "Retour à l'article" +manuscript-meca-bundle: "Archive MECA" + +section-title-abstract: "Résumé" +section-title-appendices: "Annexes" +section-title-footnotes: "Notes de bas de page" +section-title-references: "Les références" +section-title-reuse: "Réutilisation" +section-title-copyright: "Droits d'auteur" +section-title-citation: "Citation" + +appendix-attribution-bibtex: "BibTeX" +appendix-attribution-cite-as: "Veuillez citer ce travail comme suit :" +appendix-view-license: "Voir la Licence" + +title-block-author-single: "Auteur·rice" +title-block-author-plural: "Auteur·rice·s" +title-block-affiliation-single: "Affiliation" +title-block-affiliation-plural: "Affiliations" +title-block-published: "Date de publication" +title-block-modified: "Modifié" +title-block-keywords: "Mots clés" + +callout-tip-title: "Astuce" +callout-note-title: "Note" +callout-warning-title: "Avertissement" +callout-important-title: "Important" +callout-caution-title: "Mise en garde" + +code-summary: "Code" + +code-line: "Ligne" +code-lines: "Lignes" + +code-tools-menu-caption: "Code" +code-tools-show-all-code: "Montrer tout le code" +code-tools-hide-all-code: "Cacher tout le code" +code-tools-view-source: "Voir les sources" +code-tools-source-code: "Code source" + +copy-button-tooltip: "Copier vers le presse-papier" +copy-button-tooltip-success: "Copié" + +repo-action-links-edit: "Modifier cette page" +repo-action-links-source: "Voir la source" +repo-action-links-issue: "Faire part d'un problème" + +back-to-top: "Retour au sommet" + +search-no-results-text: "Pas de résultats" +search-matching-documents-text: "documents trouvés" +search-copy-link-title: "Copier le lien vers la recherche" +search-hide-matches-text: "Cacher les correspondances additionnelles" +search-more-match-text: "correspondance de plus dans ce document" +search-more-matches-text: "correspondances de plus dans ce document" +search-clear-button-title: "Effacer" +search-text-placeholder: "" +search-detached-cancel-button-title: "Annuler" +search-submit-button-title: "Envoyer" +search-label: "Recherche" + +toggle-section: "Basculer la section" +toggle-sidebar: "Basculer la barre latérale" +toggle-dark-mode: "Basculer le mode sombre" +toggle-reader-mode: "Basculer en mode lecteur" +toggle-navigation: "Basculer la navigation" + +crossref-fig-title: "Figure" +crossref-tbl-title: "Table" +crossref-lst-title: "Listing" +crossref-thm-title: "Théorème" +crossref-lem-title: "Lemme" +crossref-cor-title: "Corollaire" +crossref-prp-title: "Proposition" +crossref-cnj-title: "Conjecture" +crossref-def-title: "Définition" +crossref-exm-title: "Exemple" +crossref-exr-title: "Exercice" +crossref-ch-prefix: "Chapitre" +crossref-apx-prefix: "Annexe" +crossref-sec-prefix: "Section" +crossref-eq-prefix: "Équation" +crossref-lof-title: "Liste des Figures" +crossref-lot-title: "Liste des Tables" +crossref-lol-title: "Liste des Listings" + +environment-proof-title: "Preuve" +environment-remark-title: "Remarque" +environment-solution-title: "Solution" + +listing-page-order-by: "Trier par" +listing-page-order-by-default: "Ordre par défaut" +listing-page-order-by-date-asc: "Le plus ancien" +listing-page-order-by-date-desc: "Le plus récent" +listing-page-order-by-number-desc: "Descendant" +listing-page-order-by-number-asc: "Ascendant" +listing-page-field-date: "Date" +listing-page-field-title: "Titre" +listing-page-field-description: "Description" +listing-page-field-author: "Auteur·rice" +listing-page-field-filename: "Nom de fichier" +listing-page-field-filemodified: "Modifié" +listing-page-field-subtitle: "Sous-titre" +listing-page-field-readingtime: "Temps de lecture" +listing-page-field-categories: "Catégories" +listing-page-minutes-compact: "{0} min." +listing-page-category-all: "Toutes" +listing-page-no-matches: "Aucun article correspondant" +listing-page-field-wordcount: "Compteur de Mots" +listing-page-words: "{0} mots" +listing-page-filter: "Filtre" + +draft: "Brouillon" diff --git a/resources/language/_language-he.yml b/resources/language/_language-he.yml new file mode 100644 index 000000000..36bb2dfd7 --- /dev/null +++ b/resources/language/_language-he.yml @@ -0,0 +1,127 @@ +toc-title-document: "תוכן עניינים" +toc-title-website: "בעמוד זה" + +related-formats-title: "תבניות אחרות" +related-notebooks-title: "מחברות" +source-notebooks-prefix: "מקור" +other-links-title: "קישורים אחרים" +code-links-title: "קישורי קוד" +launch-dev-container-title: "הפעל את סביבת המפתחים" +launch-binder-title: "הפעל את Binder" + +article-notebook-label: "מחברת מאמרים" +notebook-preview-download: "הורד מחברת" +notebook-preview-download-src: "הורד מקור" +notebook-preview-back: "חזרה למאמר" +manuscript-meca-bundle: "חבילת MECA" + +section-title-abstract: "תקציר" +section-title-appendices: "נספחים" +section-title-footnotes: "הערות שוליים" +section-title-references: "מקורות" +section-title-reuse: "שימוש חוזר" +section-title-copyright: "זכויות יוצרים" +section-title-citation: "ציטוט" + +appendix-attribution-cite-as: "לצורך ייחוס, נא לצטט עבודה זו בתור:" +appendix-attribution-bibtex: "ציטוט BibTex:" +appendix-view-license: "צפה ברישיון" + +title-block-author-single: "כותב" +title-block-author-plural: "כותבים" +title-block-affiliation-single: "שיוך" +title-block-affiliation-plural: "שיוכים" +title-block-published: "פורסם" +title-block-modified: "שונה" +title-block-keywords: "מילות מפתח" + +callout-tip-title: "עצה" +callout-note-title: "הערה" +callout-warning-title: "אזהרה" +callout-important-title: "חשוב" +callout-caution-title: "זהירות" + +code-summary: "קוד" + +code-tools-menu-caption: "קוד" +code-tools-show-all-code: "הראה את הקוד כולו" +code-tools-hide-all-code: "הסתר את הקוד כולו" +code-tools-view-source: "הצג מקור" +code-tools-source-code: "קוד מקור" + +code-line: "שורה" +code-lines: "שורות" + +copy-button-tooltip: "העתק ללוח" +copy-button-tooltip-success: "הועתק!" + +repo-action-links-edit: "ערוך עמוד זה" +repo-action-links-source: "הצג מקור" +repo-action-links-issue: "דווח על בעיה" + +back-to-top: "חזרה למעלה" + +search-no-results-text: "אין תוצאות" +search-matching-documents-text: "מסמכים תואמים" +search-copy-link-title: "העתק קישור לחיפוש" +search-hide-matches-text: "הסתר התאמות נוספות" +search-more-match-text: "התאמה נוספת במסמך זה" +search-more-matches-text: "התאמות נוספות במסמך זה" +search-clear-button-title: "נקה" +search-text-placeholder: "" +search-detached-cancel-button-title: "בטל" +search-submit-button-title: "שלח" +search-label: "חפש" + +toggle-section: "הצג/הסתר מקטע" +toggle-sidebar: "הצג/הסתר את סרגל הניווט" +toggle-dark-mode: "הצג/הסתר מצב חשוך" +toggle-reader-mode: "הצג/הסתר מצב קריאה" +toggle-navigation: "הצג/הסתר ניווט" + +crossref-fig-title: "תרשים" +crossref-tbl-title: "טבלה" +crossref-lst-title: "רישום" +crossref-thm-title: "משפט" +crossref-lem-title: "לֶמה" +crossref-cor-title: "תוצאה ישירה" +crossref-prp-title: "הצעה" +crossref-cnj-title: "סברה" +crossref-def-title: "הגדרה" +crossref-exm-title: "דוגמה" +crossref-exr-title: "תרגיל" +crossref-ch-prefix: "פרק" +crossref-apx-prefix: "נספח" +crossref-sec-prefix: "מדור" +crossref-eq-prefix: "משוואה" +crossref-lof-title: "רשימת תרשימים" +crossref-lot-title: "רשימת טבלאות" +crossref-lol-title: "רשימת רישומים" + +environment-proof-title: "הוכחה" +environment-remark-title: "הערה" +environment-solution-title: "פתרון" + +listing-page-order-by: "סדר לפי" +listing-page-order-by-default: "ברירת מחדל" +listing-page-order-by-date-asc: "הישן ביותר" +listing-page-order-by-date-desc: "החדש ביותר" +listing-page-order-by-number-desc: "מגבוה לנמוך" +listing-page-order-by-number-asc: "מנמוך לגבוה" +listing-page-field-date: "תאריך" +listing-page-field-title: "כותרת" +listing-page-field-description: "תיאור" +listing-page-field-author: "כותב" +listing-page-field-filename: "שם קובץ" +listing-page-field-filemodified: "שונה" +listing-page-field-subtitle: "תת-כותרת" +listing-page-field-readingtime: "זמן קריאה" +listing-page-field-wordcount: "ספירת מילים" +listing-page-field-categories: "קטגוריום" +listing-page-minutes-compact: "{0} דק׳" +listing-page-category-all: "הכל" +listing-page-no-matches: "אין פריטים תואמים" +listing-page-words: "{0} מילים" +listing-page-filter: "מסנן" + +draft: "טְיוּטָה" diff --git a/resources/language/_language-id.yml b/resources/language/_language-id.yml new file mode 100644 index 000000000..26d895af8 --- /dev/null +++ b/resources/language/_language-id.yml @@ -0,0 +1,127 @@ +toc-title-document: "Daftar Isi" +toc-title-website: "Di halaman ini" + +related-formats-title: "Format Lain" +related-notebooks-title: "Notes" +source-notebooks-prefix: "Sumber" +other-links-title: "Tautan Lain" +code-links-title: "Tautan Kode" +launch-dev-container-title: "Mulai Dev Container" +launch-binder-title: "Mulai Binder" + +article-notebook-label: "Buku Catatan Artikel" +notebook-preview-download: "Unduh Buku Catatan" +notebook-preview-download-src: "Unduh sumber" +notebook-preview-back: "Kembali ke Artikel" +manuscript-meca-bundle: "Arsip MECA" + +section-title-abstract: "Abstrak" +section-title-appendices: "Lampiran" +section-title-footnotes: "Catatan Kaki" +section-title-references: "Daftar Pustaka" +section-title-reuse: "Guna Ulang" +section-title-copyright: "Hak Cipta" +section-title-citation: "Kutipan" + +appendix-attribution-cite-as: "Untuk atribusi, mohon kutip karya ini sebagai:" +appendix-attribution-bibtex: "Kutipan BibTeX:" +appendix-view-license: "Lihat Lisensi" + +title-block-author-single: "Penulis" +title-block-author-plural: "Penulis" +title-block-affiliation-single: "Afiliasi" +title-block-affiliation-plural: "Afiliasi" +title-block-published: "Diterbitkan" +title-block-modified: "Diubah" +title-block-keywords: "Kata kunci" + +callout-tip-title: "Tip" +callout-note-title: "Catatan" +callout-warning-title: "Peringatan" +callout-important-title: "Penting" +callout-caution-title: "Bahaya" + +code-summary: "Kode" + +code-tools-menu-caption: "Kode" +code-tools-show-all-code: "Tampilkan Semua Kode" +code-tools-hide-all-code: "Sembunyikan Semua Kode" +code-tools-view-source: "Lihat Sumber" +code-tools-source-code: "Kode Sumber" + +code-line: "Baris" +code-lines: "Baris" + +copy-button-tooltip: "Salin ke Papan Klip" +copy-button-tooltip-success: "Disalin!" + +repo-action-links-edit: "Sunting laman ini" +repo-action-links-source: "Lihat sumber" +repo-action-links-issue: "Laporkan isu" + +back-to-top: "Kembali ke atas" + +search-no-results-text: "Tidak ada hasil" +search-matching-documents-text: "dokumen cocok" +search-copy-link-title: "Salin tautan untuk mencari" +search-hide-matches-text: "Sembunyikan kecocokan lainnya" +search-more-match-text: "kecocokan lainnya di dokumen ini" +search-more-matches-text: "kecocokan lainnya di dokumen ini" +search-clear-button-title: "Hapus" +search-text-placeholder: "" +search-detached-cancel-button-title: "Batal" +search-submit-button-title: "Kirim" +search-label: "Mencari" + +toggle-section: "Alihkan bagian" +toggle-sidebar: "Alihkan bilah sisi" +toggle-dark-mode: "Alihkan mode gelap" +toggle-reader-mode: "Alihkan mode pembaca" +toggle-navigation: "Alihkan navigasi" + +crossref-fig-title: "Gambar" +crossref-tbl-title: "Tabel" +crossref-lst-title: "Daftar" +crossref-thm-title: "Teorema" +crossref-lem-title: "Lema" +crossref-cor-title: "Korolari" +crossref-prp-title: "Proposisi" +crossref-cnj-title: "Dugaan" +crossref-def-title: "Definisi" +crossref-exm-title: "Contoh" +crossref-exr-title: "Latihan" +crossref-ch-prefix: "Bab" +crossref-apx-prefix: "Lampiran" +crossref-sec-prefix: "Bagian" +crossref-eq-prefix: "Perhitungan" +crossref-lof-title: "Daftar Gambar" +crossref-lot-title: "Daftar Tabel" +crossref-lol-title: "Daftar Daftar" + +environment-proof-title: "Bukti" +environment-remark-title: "Keterangan" +environment-solution-title: "Pemecahan" + +listing-page-order-by: "Urut berdasar" +listing-page-order-by-default: "Default" +listing-page-order-by-date-asc: "Paling lama" +listing-page-order-by-date-desc: "Paling baru" +listing-page-order-by-number-desc: "Tinggi ke rendah" +listing-page-order-by-number-asc: "Rendah ke tinggi" +listing-page-field-date: "Tanggal" +listing-page-field-title: "Judul" +listing-page-field-description: "Deskripsi" +listing-page-field-author: "Penulis" +listing-page-field-filename: "Nama Berkas" +listing-page-field-filemodified: "Diubah pada" +listing-page-field-subtitle: "Subjudul" +listing-page-field-readingtime: "Waktu Baca" +listing-page-field-categories: "Kategori" +listing-page-minutes-compact: "{0} menit" +listing-page-category-all: "Semua" +listing-page-no-matches: "Tidak ada yang cocok" +listing-page-field-wordcount: "Hitung Kata" +listing-page-words: "{0} kata" +listing-page-filter: "Filter" + +draft: "Draf" diff --git a/resources/language/_language-is.yml b/resources/language/_language-is.yml new file mode 100644 index 000000000..43a319c42 --- /dev/null +++ b/resources/language/_language-is.yml @@ -0,0 +1,130 @@ +toc-title-document: "Efnisyfirlit" +toc-title-website: "Á þessari síðu" + +related-formats-title: "Önnur sniðmát" +related-notebooks-title: "Skrifblokkir" +source-notebooks-prefix: "Frumkóði" +other-links-title: "Aðrar krækjur" +code-links-title: "Kóðakrækjur" +launch-dev-container-title: "Ræsa þróunarílát" +launch-binder-title: "Ræsa heftara" + +article-notebook-label: "Greinarblokk" +notebook-preview-download: "Hala niður skrifblokk" +notebook-preview-download-src: "Hala niður frumkóða" +notebook-preview-back: "Tilbaka í grein" +manuscript-meca-bundle: "MECA knippi" + +section-title-abstract: "Ágrip" +section-title-appendices: "Viðaukar" +section-title-footnotes: "Neðanmálsgreinar" +section-title-references: "Heimildir" +section-title-reuse: "Endurnota" +section-title-copyright: "Höfundarréttur" +section-title-citation: "Tilvitnun" + +appendix-attribution-cite-as: "Vinsamlega vitnið til þessa verk sem:" +appendix-attribution-bibtex: "BibTeX tilvitnun:" +appendix-view-license: "Skoða notendaskilmála" + +title-block-author-single: "Höfundur" +title-block-author-plural: "Höfundar" +title-block-affiliation-single: "Tengsl" +title-block-affiliation-plural: "Tengsl" +title-block-published: "Birt" +title-block-modified: "Breytt" +title-block-keywords: "Lykilorð" + +callout-tip-title: "Ábending" +callout-note-title: "Athugasemd" +callout-warning-title: "Aðvörun" +callout-important-title: "Mikilvægt" +callout-caution-title: "Varúð" + +code-summary: "Kóði" + +code-tools-menu-caption: "Kóði" +code-tools-show-all-code: "Sýna allan kóða" +code-tools-hide-all-code: "Fela allan kóða" +code-tools-view-source: "Skoða frumkóða" +code-tools-source-code: "Frumkóði" + +tools-share: "Deila" +tools-download: "Hala niður" + +code-line: "Lína" +code-lines: "Línur" + +copy-button-tooltip: "Afrita á klemmuspjald" +copy-button-tooltip-success: "Afritað!" + +repo-action-links-edit: "Breyta þessari síðu" +repo-action-links-source: "Skoða frumkóða" +repo-action-links-issue: "Tilkynna mál" + +back-to-top: "Efst á síðu" + +search-no-results-text: "Engar niðurstöður" +search-matching-documents-text: "Skjöl sem passa" +search-copy-link-title: "Afrita krækju í leitarglugga" +search-hide-matches-text: "Fela aðrar samsvarandi niðurstöður" +search-more-match-text: "önnur samsvörun í þessu skjali" +search-more-matches-text: "aðrar samsvaranir í þessu skjali" +search-clear-button-title: "Eyða" +search-text-placeholder: "" +search-detached-cancel-button-title: "Hætta við" +search-submit-button-title: "Senda inn" +search-label: "Leita" + +toggle-section: "Víxla undirkafla" +toggle-sidebar: "Víxla hliðarslá" +toggle-dark-mode: "Víxla næturham" +toggle-reader-mode: "Víxla lestrarham" +toggle-navigation: "Víxla stiklurönd" + +crossref-fig-title: "Mynd" +crossref-tbl-title: "Tafla" +crossref-lst-title: "Listun" +crossref-thm-title: "Setning" +crossref-lem-title: "Hjálparsetning" +crossref-cor-title: "Fylgisetning" +crossref-prp-title: "Yrðing" +crossref-cnj-title: "Tilgáta" +crossref-def-title: "Skilgreining" +crossref-exm-title: "Dæmi" +crossref-exr-title: "Verkefni" +crossref-ch-prefix: "Kafli" +crossref-apx-prefix: "Viðauki" +crossref-sec-prefix: "Undirkafli" +crossref-eq-prefix: "Jafna" +crossref-lof-title: "Myndayfirlit" +crossref-lot-title: "Töfluyfirlit" +crossref-lol-title: "Listanayfirlit" + +environment-proof-title: "Sönnun" +environment-remark-title: "Athugasemd" +environment-solution-title: "Lausn" + +listing-page-order-by: "Raða eftir" +listing-page-order-by-default: "Sjálfgefið" +listing-page-order-by-date-asc: "Elsta" +listing-page-order-by-date-desc: "Nýjasta" +listing-page-order-by-number-desc: "Hæsta til lægsta" +listing-page-order-by-number-asc: "Lægsta til hæsta" +listing-page-field-date: "Dagsetning" +listing-page-field-title: "Titill" +listing-page-field-description: "Lýsing" +listing-page-field-author: "Höfundur" +listing-page-field-filename: "Skráarnafn" +listing-page-field-filemodified: "Breytt" +listing-page-field-subtitle: "Undirtitill" +listing-page-field-readingtime: "Lestími" +listing-page-field-wordcount: "Orðatalning" +listing-page-field-categories: "Efnisflokkar" +listing-page-minutes-compact: "{0} mín" +listing-page-category-all: "Allt" +listing-page-no-matches: "Engin samsvörun" +listing-page-words: "{0} orð" +listing-page-filter: "Sía" + +draft: "Drög" diff --git a/resources/language/_language-it.yml b/resources/language/_language-it.yml new file mode 100644 index 000000000..5cb4d00f4 --- /dev/null +++ b/resources/language/_language-it.yml @@ -0,0 +1,127 @@ +toc-title-document: "Indice" +toc-title-website: "In questa pagina" + +related-formats-title: "Altri Formati" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "Fonte" +other-links-title: "Altri Link" +code-links-title: "Collegamenti al Codice" +launch-dev-container-title: "Avvia Dev Container" +launch-binder-title: "Avvia Binder" + +article-notebook-label: "Quaderno dell'Articolo" +notebook-preview-download: "Scarica il Quaderno" +notebook-preview-download-src: "Scarica codice sorgente" +notebook-preview-back: "Torna all'Articolo" +manuscript-meca-bundle: "Archivio MECA" + +section-title-abstract: "Sommario" +section-title-appendices: "Appendici" +section-title-footnotes: "Note" +section-title-references: "Referenze" +section-title-reuse: "Riutilizzare" +section-title-copyright: "Diritto d'autore" +section-title-citation: "Citazione" + +appendix-attribution-bibtex: "BibTeX" +appendix-attribution-cite-as: "Per favore citare questo lavoro come:" +appendix-view-license: "Visualizza Licenza" + +title-block-author-single: "Autore/Autrice" +title-block-author-plural: "Autori" +title-block-affiliation-single: "Affiliazione" +title-block-affiliation-plural: "Affiliazioni" +title-block-published: "Data di Pubblicazione" +title-block-modified: "Data di modifica" +title-block-keywords: "Parole chiave" + +callout-tip-title: "Consiglio" +callout-note-title: "Nota" +callout-warning-title: "Avviso" +callout-important-title: "Importante" +callout-caution-title: "Attenzione" + +code-summary: "Codice" + +code-line: "Linea" +code-lines: "Linee" + +code-tools-menu-caption: "Codice" +code-tools-show-all-code: "Mostra il codice" +code-tools-hide-all-code: "Nascondere il codice" +code-tools-view-source: "Vedere il codice" +code-tools-source-code: "Eseguire il codice" + +copy-button-tooltip: "Copia negli appunti" +copy-button-tooltip-success: "Copiato!" + +repo-action-links-edit: "Modifica questa pagina" +repo-action-links-source: "Mostra il codice" +repo-action-links-issue: "Segnala un problema" + +back-to-top: "Torna in cima" + +search-no-results-text: "Nessun risultato" +search-matching-documents-text: "documenti trovati" +search-copy-link-title: "Copiare il link nella ricerca" +search-hide-matches-text: "Nascondere i risultati aggiuntivi" +search-more-match-text: "ci sono altri risultati in questo documento" +search-more-matches-text: "ulteriori risultati in questo documento" +search-clear-button-title: "Pulire" +search-text-placeholder: "" +search-detached-cancel-button-title: "Cancellare" +search-submit-button-title: "Inviare" +search-label: "Ricerca" + +toggle-section: "Attiva/disattiva sezione" +toggle-sidebar: "Attiva/disattiva la barra laterale" +toggle-dark-mode: "Attiva/disattiva la modalità oscura" +toggle-reader-mode: "Attiva/disattiva la modalità lettore" +toggle-navigation: "Attiva/disattiva la navigazione" + +crossref-fig-title: "Figura" +crossref-tbl-title: "Tabella" +crossref-lst-title: "Lista" +crossref-thm-title: "Teorema" +crossref-lem-title: "Lemma" +crossref-cor-title: "Corollario" +crossref-prp-title: "Proposizione" +crossref-cnj-title: "Congettura" +crossref-def-title: "Definizione" +crossref-exm-title: "Esempio" +crossref-exr-title: "Esercizio" +crossref-ch-prefix: "Capitolo" +crossref-apx-prefix: "Appendice" +crossref-sec-prefix: "Sezione" +crossref-eq-prefix: "Equazione" +crossref-lof-title: "Elenco delle Figure" +crossref-lot-title: "Elenco delle Tabelle" +crossref-lol-title: "Elenco degli Elenchi" + +environment-proof-title: "Dimostrazione" +environment-remark-title: "Osservazione" +environment-solution-title: "Soluzione" + +listing-page-order-by: "Ordinare per" +listing-page-order-by-default: "Predefinito" +listing-page-order-by-date-asc: "Meno recente" +listing-page-order-by-date-desc: "Più recente" +listing-page-order-by-number-desc: "Numero da maggiore a minore" +listing-page-order-by-number-asc: "Numero da minore a maggiore" +listing-page-field-date: "Data" +listing-page-field-title: "Titolo" +listing-page-field-description: "Descrizione" +listing-page-field-author: "Autore/Autrice" +listing-page-field-filename: "Nome del file" +listing-page-field-filemodified: "Data di modifica" +listing-page-field-subtitle: "Sottotitolo" +listing-page-field-readingtime: "Tempo per completare la lettura" +listing-page-field-categories: "Categorie" +listing-page-minutes-compact: "{0} minuti" +listing-page-category-all: "Tutti" +listing-page-no-matches: "Nessun risultato" +listing-page-field-wordcount: "Conteggio Parole" +listing-page-words: "{0} parole" +listing-page-filter: "Filtro" + +draft: "Bozza" diff --git a/resources/language/_language-ja.yml b/resources/language/_language-ja.yml new file mode 100644 index 000000000..d022bacf4 --- /dev/null +++ b/resources/language/_language-ja.yml @@ -0,0 +1,127 @@ +toc-title-document: "目次" +toc-title-website: "目次" + +related-formats-title: "その他のフォーマット" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "ソース" +other-links-title: "その他のリンク" +code-links-title: "コードリンクス" +launch-dev-container-title: "Devコンテナを起動する" +launch-binder-title: "ランチ Binder" + +article-notebook-label: "記事ノート" +notebook-preview-download: "ノートブックをダウンロード" +notebook-preview-download-src: "ソースコードをダウンロードする" +notebook-preview-back: "記事に戻る" +manuscript-meca-bundle: "MECAアーカイブ" + +section-title-abstract: "概要" +section-title-appendices: "付録" +section-title-footnotes: "脚注" +section-title-references: "参考文献" +section-title-reuse: "ライセンス" +section-title-copyright: "著作権" +section-title-citation: "引用" + +appendix-attribution-cite-as: "引用方法" +appendix-attribution-bibtex: "BibTeX" +appendix-view-license: "ライセンスを表示" + +title-block-author-single: "作者" +title-block-author-plural: "作者" +title-block-affiliation-single: "所属" +title-block-affiliation-plural: "所属" +title-block-published: "公開" +title-block-modified: "更新日" +title-block-keywords: "キーワード" + +callout-tip-title: "ヒント" +callout-note-title: "ノート" +callout-warning-title: "警告" +callout-important-title: "重要" +callout-caution-title: "注意" + +code-summary: "コード" + +code-line: "ライン" +code-lines: "ライン" + +code-tools-menu-caption: "コード" +code-tools-show-all-code: "すべてのコードを表示" +code-tools-hide-all-code: "すべてのコードを非表示" +code-tools-view-source: "ソースコードを表示" +code-tools-source-code: "ソースコード" + +copy-button-tooltip: "コピー" +copy-button-tooltip-success: "コピーしました" + +repo-action-links-edit: "編集" +repo-action-links-source: "ソースコード" +repo-action-links-issue: "問題を報告" + +back-to-top: "トップに戻る" + +search-no-results-text: "一致なし" +search-matching-documents-text: "一致した文書" +search-copy-link-title: "検索へのリンクをコピー" +search-hide-matches-text: "追加の検索結果を非表示" +search-more-match-text: "追加の検索結果" +search-more-matches-text: "追加の検索結果" +search-clear-button-title: "消去" +search-text-placeholder: "" +search-detached-cancel-button-title: "取消" +search-submit-button-title: "検索" +search-label: "サーチ" + +toggle-section: "セクションを切り替え" +toggle-sidebar: "サイドバーを切り替える" +toggle-dark-mode: "ダークモードの切り替え" +toggle-reader-mode: "リーダーモードの切り替え" +toggle-navigation: "ナビゲーションを切り替える" + +crossref-fig-title: "図" +crossref-tbl-title: "表" +crossref-lst-title: "コード" +crossref-thm-title: "定理" +crossref-lem-title: "補題" +crossref-cor-title: "系" +crossref-prp-title: "命題" +crossref-cnj-title: "予想" +crossref-def-title: "定義" +crossref-exm-title: "例" +crossref-exr-title: "練習" +crossref-ch-prefix: "チャプター" +crossref-apx-prefix: "付録" +crossref-sec-prefix: "セクション" +crossref-eq-prefix: "式" +crossref-lof-title: "図一覧" +crossref-lot-title: "表一覧" +crossref-lol-title: "コード一覧" + +environment-proof-title: "証明" +environment-remark-title: "注釈" +environment-solution-title: "解答" + +listing-page-order-by: "並び替え" +listing-page-order-by-default: "デフォルト" +listing-page-order-by-date-asc: "日付(昇順)" +listing-page-order-by-date-desc: "日付(降順)" +listing-page-order-by-number-desc: "ページ番号(降順)" +listing-page-order-by-number-asc: "ページ番号(昇順)" +listing-page-field-date: "日付" +listing-page-field-title: "題名" +listing-page-field-description: "説明" +listing-page-field-author: "作者" +listing-page-field-filename: "ファイル名" +listing-page-field-filemodified: "更新日" +listing-page-field-subtitle: "副題" +listing-page-field-readingtime: "読了目安" +listing-page-field-categories: "分類" +listing-page-minutes-compact: "{0} 分" +listing-page-category-all: "すべて" +listing-page-no-matches: "一致なし" +listing-page-field-wordcount: "単語数" +listing-page-words: "{0}語" +listing-page-filter: "フィルター" + +draft: "下書き" diff --git a/resources/language/_language-ko.yml b/resources/language/_language-ko.yml new file mode 100644 index 000000000..fd7b0a56e --- /dev/null +++ b/resources/language/_language-ko.yml @@ -0,0 +1,126 @@ +toc-title-document: "목차" +toc-title-website: "목차" + +related-formats-title: "기타 형식" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "원천" +other-links-title: "기타 링크" +code-links-title: "코드 링크" +launch-dev-container-title: "Dev 컨테이너 실행" +launch-binder-title: "랜치 Binder" + +article-notebook-label: "기사 노트북" +notebook-preview-download: "노트북 다운로드" +notebook-preview-download-src: "소스 다운로드" +notebook-preview-back: "기사로 돌아가기" +manuscript-meca-bundle: "MECA 아카이브" + +section-title-abstract: "초록" +section-title-appendices: "부록" +section-title-footnotes: "각주" +section-title-references: "참고문헌" +section-title-reuse: "라이센스" +section-title-copyright: "저작권" +section-title-citation: "인용" + +appendix-attribution-cite-as: "인용방법" +appendix-attribution-bibtex: "BibTeX 인용:" +appendix-view-license: "라이센스 보기" + +title-block-author-single: "저자" +title-block-author-plural: "저자" +title-block-affiliation-single: "소속" +title-block-affiliation-plural: "소속" +title-block-published: "공개" +title-block-keywords: "키워드" + +callout-tip-title: "힌트" +callout-note-title: "노트" +callout-warning-title: "경고" +callout-important-title: "중요" +callout-caution-title: "주의" + +code-summary: "코드" + +code-line: "선" +code-lines: "윤곽" + +code-tools-menu-caption: "코드" +code-tools-show-all-code: "전체 코드 표시" +code-tools-hide-all-code: "전체 코드 숨기기" +code-tools-view-source: "소스 코드 표시" +code-tools-source-code: "소스 코드" + +copy-button-tooltip: "클립보드 복사" +copy-button-tooltip-success: "복사완료!" + +repo-action-links-edit: "편집" +repo-action-links-source: "소스코드 보기" +repo-action-links-issue: "이슈 보고" + +back-to-top: "맨 위로" + +search-no-results-text: "일치 없음" +search-matching-documents-text: "일치된 문서" +search-copy-link-title: "검색 링크 복사" +search-hide-matches-text: "추가 검색 결과 숨기기" +search-more-match-text: "추가 검색결과" +search-more-matches-text: "추가 검색결과" +search-clear-button-title: "제거" +search-text-placeholder: "" +search-detached-cancel-button-title: "취소" +search-submit-button-title: "검색" +search-label: "검색" + +toggle-section: "토글 섹션" +toggle-sidebar: "사이드바 전환" +toggle-dark-mode: "다크 모드 전환" +toggle-reader-mode: "리더 모드 전환" +toggle-navigation: "탐색 전환" + +crossref-fig-title: "그림" +crossref-tbl-title: "표" +crossref-lst-title: "목록" +crossref-thm-title: "정리" +crossref-lem-title: "보조정리" +crossref-cor-title: "따름정리" +crossref-prp-title: "명제" +crossref-cnj-title: "추측" +crossref-def-title: "정의" +crossref-exm-title: "보기" +crossref-exr-title: "예제" +crossref-ch-prefix: "장" +crossref-apx-prefix: "부록" +crossref-sec-prefix: "섹션" +crossref-eq-prefix: "방정식" +crossref-lof-title: "그림 목록" +crossref-lot-title: "표 목록" +crossref-lol-title: "코드 목록" + +environment-proof-title: "증명" +environment-remark-title: "주석" +environment-solution-title: "해답" + +listing-page-order-by: "정렬" +listing-page-order-by-default: "디폴트" +listing-page-order-by-date-asc: "날짜(오름차순)" +listing-page-order-by-date-desc: "날짜(내림차순)" +listing-page-order-by-number-desc: "페이지 번호(내림차순)" +listing-page-order-by-number-asc: "페이지 번호(오름차순)" +listing-page-field-date: "날짜" +listing-page-field-title: "제목" +listing-page-field-description: "설명" +listing-page-field-author: "저자" +listing-page-field-filename: "파일명" +listing-page-field-filemodified: "갱신일" +listing-page-field-subtitle: "부제목" +listing-page-field-readingtime: "읽기 시간" +listing-page-field-categories: "분류" +listing-page-minutes-compact: "{0} 분" +listing-page-category-all: "전체" +listing-page-no-matches: "일치 없음" +listing-page-field-wordcount: "단어 수" +listing-page-words: "{0} 단어" +listing-page-filter: "필터" + +draft: "초안" diff --git a/resources/language/_language-lt.yml b/resources/language/_language-lt.yml new file mode 100644 index 000000000..c9d34ee5a --- /dev/null +++ b/resources/language/_language-lt.yml @@ -0,0 +1,127 @@ +toc-title-document: "Turinys" +toc-title-website: "Šiame tinklalapyje" + +related-formats-title: "Kiti formatai" +related-notebooks-title: "Užrašų knygutės" +source-notebooks-prefix: "Pirminis dokumentas" +other-links-title: "Kiti nuorodos" +code-links-title: "Kodo nuorodos" +launch-dev-container-title: "Paleisti Dev Container" +launch-binder-title: "Paleisti Binder" + +article-notebook-label: "Straipsnio užrašų knygelė" +notebook-preview-download: "Atsisiųsti užrašų knygelę" +notebook-preview-download-src: "Parsisiųsti šaltinio kodą" +notebook-preview-back: "Grįžti į straipsnį" +manuscript-meca-bundle: "MECA archyvas" + +section-title-abstract: "Santrauka" +section-title-appendices: "Priedai" +section-title-footnotes: "Pastabos" +section-title-references: "Informacijos šaltiniai" +section-title-reuse: "Perpanaudojimas" +section-title-copyright: "Autorių teisės" +section-title-citation: "Citavimas" + +appendix-attribution-cite-as: "Prašome šį darbą cituoti kaip:" +appendix-attribution-bibtex: "BibTeX citavimas:" +appendix-view-license: "Peržiūrėti Licenciją" + +title-block-author-single: "Autorius" +title-block-author-plural: "Autoriai" +title-block-affiliation-single: "Organizacija" +title-block-affiliation-plural: "Organizacijos" +title-block-published: "Paskelbta" +title-block-modified: "Atnaujinta" +title-block-keywords: "Raktiniai žodžiai" + +callout-tip-title: "Patarimas" +callout-note-title: "Pastaba" +callout-warning-title: "Įspėjimas" +callout-important-title: "Svarbu" +callout-caution-title: "Atsargiai" + +code-summary: "Kodas" + +code-tools-menu-caption: "Kodas" +code-tools-show-all-code: "Rodyti visą kodą" +code-tools-hide-all-code: "Slėpti visą kodą" +code-tools-view-source: "Rodyti pirminį kodą" +code-tools-source-code: "Pirminis kodas" + +code-line: "Eilutė" +code-lines: "Eilutės" + +copy-button-tooltip: "Kopijuoti į iškarpinę" +copy-button-tooltip-success: "Nukopijuota!" + +repo-action-links-edit: "Redaguoti šį tinklalapį" +repo-action-links-source: "Rodyti pirminį dokumentą/kodą" +repo-action-links-issue: "Pranešti apie problemą" + +back-to-top: "Grįžti į viršų" + +search-no-results-text: "Nėra rezultatų" +search-matching-documents-text: "atitinkančių dokumentų" +search-copy-link-title: "Kopijuoti nuorodą į paiešką" +search-hide-matches-text: "Slėpti kitus atitikimus" +search-more-match-text: "daugiau atitikimų šiame dokumente" +search-more-matches-text: "daugiau atitikimų šiame dokumente" +search-clear-button-title: "Išvalyti" +search-text-placeholder: "" +search-detached-cancel-button-title: "Atšaukti" +search-submit-button-title: "Pateikti" +search: "Paieška" + +toggle-section: "Rodyti/Slėpti skiltį" +toggle-sidebar: "Rodyti/Slėpti šoninę navigacijos skiltį" +toggle-dark-mode: "Išjungti/Įjungti tamsųjį režimą" +toggle-reader-mode: "Išjungti/Įjungti skaitymo režimą" +toggle-navigation: "Rodyti/Slėpti navigaciją" + +crossref-fig-title: "Paveikslas" +crossref-tbl-title: "Lentelė" +crossref-lst-title: "Sąrašas" +crossref-thm-title: "Teorema" +crossref-lem-title: "Lema" +crossref-cor-title: "Išvada" +crossref-prp-title: "Teiginys" +crossref-cnj-title: "Hipotezė" +crossref-def-title: "Apibrėžimas" +crossref-exm-title: "Pavyzdys" +crossref-exr-title: "Užduotis" +crossref-ch-prefix: "Skyrius" +crossref-apx-prefix: "Priedas" +crossref-sec-prefix: "Poskyris" +crossref-eq-prefix: "Lygtis" +crossref-lof-title: "Paveikslių sąrašas" +crossref-lot-title: "Lentelių sąrašas" +crossref-lol-title: "Temų sąrašas" + +environment-proof-title: "Įrodymas" +environment-remark-title: "Pastaba" +environment-solution-title: "Sprendimas" + +listing-page-order-by: "Rikiavimas" +listing-page-order-by-default: "Numatytasis" +listing-page-order-by-date-asc: "Seniausi pradžioje" +listing-page-order-by-date-desc: "Naujausi pradžioje" +listing-page-order-by-number-desc: "Nuo didžiausio iki mažiausio" +listing-page-order-by-number-asc: "Nuo mažiausio iki didžiausio" +listing-page-field-date: "Data" +listing-page-field-title: "Pavadinimas" +listing-page-field-description: "Aprašymas" +listing-page-field-author: "Autorius" +listing-page-field-filename: "Bylos pavadinimas" +listing-page-field-filemodified: "Modifikuota" +listing-page-field-subtitle: "Paantraštė" +listing-page-field-readingtime: "Skaitymo trukmė" +listing-page-field-categories: "Kategorijos" +listing-page-minutes-compact: "{0} min" +listing-page-category-all: "Viskas" +listing-page-no-matches: "Atitinkančių elementų nerasta" +listing-page-field-wordcount: "Žodžių Skaičius" +listing-page-words: "{0} žodžiai" +listing-page-filter: "Filtras" + +draft: "Juodraštis" diff --git a/resources/language/_language-nb.yml b/resources/language/_language-nb.yml new file mode 100644 index 000000000..46397d3ca --- /dev/null +++ b/resources/language/_language-nb.yml @@ -0,0 +1,127 @@ +toc-title-document: "Innholdsfortegnelse" +toc-title-website: "På denne siden" + +related-formats-title: "Andre formater" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "Kilde" +other-links-title: "Andre lenker" +code-links-title: "Kodelenker" +launch-dev-container-title: "Start Dev Container" +launch-binder-title: "Start Binder" + +article-notebook-label: "Artikkelskrivebok" +notebook-preview-download: "Last ned skrivebok" +notebook-preview-download-src: "Last ned kildekode" +notebook-preview-back: "Tilbake til artikkelen" +manuscript-meca-bundle: "MECA-arkiv" + +section-title-abstract: "Sammendrag" +section-title-appendices: "Bilag" +section-title-footnotes: "Fotnoter" +section-title-references: "Referanser" +section-title-reuse: "Gjenbruk" +section-title-copyright: "Opphavsrett" +section-title-citation: "Sitat" + +appendix-attribution-bibtex: "Henvis til dette arbeidet som:" +appendix-attribution-cite-as: "BibTeX henvisning:" +appendix-view-license: "Vis Lisens" + +title-block-author-single: "Forfatter" +title-block-author-plural: "Forfattere" +title-block-affiliation-single: "Tilknytning" +title-block-affiliation-plural: "Tilknytninger" +title-block-published: "Utgitt" +title-block-modified: "Endret" +title-block-keywords: "Nøkkelord" + +callout-tip-title: "Tips" +callout-note-title: "Note" +callout-warning-title: "Advarsel" +callout-important-title: "Viktig" +callout-caution-title: "Forsiktig" + +code-summary: "Kode" + +code-line: "Linje" +code-lines: "Linjer" + +code-tools-menu-caption: "Kode" +code-tools-show-all-code: "Vis all kode" +code-tools-hide-all-code: "Skjul all kode" +code-tools-view-source: "Vis kilde" +code-tools-source-code: "Kildekode" + +copy-button-tooltip: "Kopier til utklipstavle" +copy-button-tooltip-success: "Kopiert!" + +repo-action-links-edit: "Endre denne siden" +repo-action-links-source: "Vis kilde" +repo-action-links-issue: "Meld om et problem" + +back-to-top: "Tilbake til toppen" + +search-no-results-text: "Ingen resultater" +search-matching-documents-text: "Samsvarende dokumenter" +search-copy-link-title: "Kopier link for å søke" +search-hide-matches-text: "Skjul ytterlige resultater" +search-more-match-text: "annet resultat i dette dokumentet" +search-more-matches-text: "andre resultater i dette dokumentet" +search-clear-button-title: "Tøm" +search-text-placeholder: "" +search-detached-cancel-button-title: "Avbryt" +search-submit-button-title: "Send inn" +search-label: "Søk" + +toggle-section: "Slå på delen" +toggle-sidebar: "Slå av eller på sidebarnavigering" +toggle-dark-mode: "Bytt mørk modus" +toggle-reader-mode: "Bytt lesermodus" +toggle-navigation: "Slå på navigering" + +crossref-fig-title: "Figur" +crossref-tbl-title: "Tabell" +crossref-lst-title: "Liste" +crossref-thm-title: "Setning" +crossref-lem-title: "Hjelpesetning" +crossref-cor-title: "Følgesetning" +crossref-prp-title: "Erklæring" +crossref-cnj-title: "Formodning" +crossref-def-title: "Definisjon" +crossref-exm-title: "Eksempel" +crossref-exr-title: "Øvelse" +crossref-ch-prefix: "Kapitel" +crossref-apx-prefix: "Bilag" +crossref-sec-prefix: "Seksjon" +crossref-eq-prefix: "Ligning" +crossref-lof-title: "Figuroversikt" +crossref-lot-title: "Tabelloversikt" +crossref-lol-title: "Listeoversikt" + +environment-proof-title: "Bevis" +environment-remark-title: "Bemerkning" +environment-solution-title: "Løsning" + +listing-page-order-by: "Sortér etter" +listing-page-order-by-default: "Standard" +listing-page-order-by-date-asc: "Eldste" +listing-page-order-by-date-desc: "Nyeste" +listing-page-order-by-number-desc: "Synkende" +listing-page-order-by-number-asc: "Stigende" +listing-page-field-date: "Dato" +listing-page-field-title: "Overskrift" +listing-page-field-description: "Beskrivelse" +listing-page-field-author: "Forfatter" +listing-page-field-filename: "Filnavn" +listing-page-field-filemodified: "Endret" +listing-page-field-subtitle: "Underoverskrift" +listing-page-field-readingtime: "Lesetid" +listing-page-field-categories: "Kategorier" +listing-page-minutes-compact: "{0} min" +listing-page-category-all: "Alle" +listing-page-no-matches: "Ingen resultater" +listing-page-field-wordcount: "Ordtelling" +listing-page-words: "{0} ord" +listing-page-filter: "Filter" + +draft: "Utkast" diff --git a/resources/language/_language-nl.yml b/resources/language/_language-nl.yml new file mode 100644 index 000000000..8ee6465d8 --- /dev/null +++ b/resources/language/_language-nl.yml @@ -0,0 +1,127 @@ +toc-title-document: "Inhoudsopgave" +toc-title-website: "Op deze pagina" + +related-formats-title: "Andere formaten" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "Bron" +other-links-title: "Andere Links" +code-links-title: "Code Links" +launch-dev-container-title: "Dev Container starten" +launch-binder-title: "Binder starten" + +article-notebook-label: "Artikel Notebook" +notebook-preview-download: "Download Notebook" +notebook-preview-download-src: "Broncode downloaden" +notebook-preview-back: "Terug naar Artikel" +manuscript-meca-bundle: "MECA Archief" + +section-title-abstract: "Samenvatting" +section-title-appendices: "Bijlagen" +section-title-footnotes: "Voetnoten" +section-title-references: "Referenties" +section-title-reuse: "Hergebruik" +section-title-copyright: "Auteursrechten" +section-title-citation: "Citaat" + +appendix-attribution-cite-as: "Citeer dit werk als:" +appendix-attribution-bibtex: "BibTeX citaat:" +appendix-view-license: "Licentie Bekijken" + +title-block-author-single: "Auteur" +title-block-author-plural: "Auteurs" +title-block-affiliation-single: "Affiliatie" +title-block-affiliation-plural: "Affiliaties" +title-block-published: "Publicatiedatum" +title-block-modified: "Gewijzigd" +title-block-keywords: "Trefwoorden" + +callout-tip-title: "Tip" +callout-note-title: "Opmerking" +callout-warning-title: "Waarschuwing" +callout-important-title: "Belangrijk" +callout-caution-title: "Opgelet" + +code-summary: "Code" + +code-line: "Regel" +code-lines: "Regels" + +code-tools-menu-caption: "Code" +code-tools-show-all-code: "Alle code tonen" +code-tools-hide-all-code: "Alle code verbergen" +code-tools-view-source: "Broncode bekijken" +code-tools-source-code: "Broncode" + +copy-button-tooltip: "Kopieer naar klembord" +copy-button-tooltip-success: "Gekopieerd!" + +repo-action-links-edit: "Pagina bewerken" +repo-action-links-source: "Broncode bekijken" +repo-action-links-issue: "Een probleem melden" + +back-to-top: "Terug naar boven" + +search-no-results-text: "Geen resultaten" +search-matching-documents-text: "Gevonden documenten" +search-copy-link-title: "Kopieer link om te zoeken" +search-hide-matches-text: "Extra overeenkomsten verbergen" +search-more-match-text: "meer overeenkomst in dit document" +search-more-matches-text: "meer overeenkomsten in dit document" +search-clear-button-title: "Wissen" +search-text-placeholder: "" +search-detached-cancel-button-title: "Annuleren" +search-submit-button-title: "Verzenden" +search-label: "Zoeken" + +toggle-section: "Schakel sectie" +toggle-sidebar: "Schakel zijbalknavigatie" +toggle-dark-mode: "Schakel donkere modus" +toggle-reader-mode: "Schakel leesmodus" +toggle-navigation: "Schakel navigatie" + +crossref-fig-title: "Figuur" +crossref-tbl-title: "Tabel" +crossref-lst-title: "Listing" +crossref-thm-title: "Stelling" +crossref-lem-title: "Lemma" +crossref-cor-title: "Conclusie" +crossref-prp-title: "Voorstel" +crossref-cnj-title: "Aanname" +crossref-def-title: "Definitie" +crossref-exm-title: "Voorbeeld" +crossref-exr-title: "Oefening" +crossref-ch-prefix: "Hoofdstuk" +crossref-apx-prefix: "Bijlage" +crossref-sec-prefix: "Paragraaf" +crossref-eq-prefix: "Vergelijking" +crossref-lof-title: "Lijst van figuren" +crossref-lot-title: "Lijst van tabellen" +crossref-lol-title: "Lijst van listings" + +environment-proof-title: "Bewijs" +environment-remark-title: "Opmerking" +environment-solution-title: "Oplossing" + +listing-page-order-by: "Sorteer op" +listing-page-order-by-default: "Standaard" +listing-page-order-by-date-asc: "Oudste" +listing-page-order-by-date-desc: "Nieuwste" +listing-page-order-by-number-desc: "Aflopend" +listing-page-order-by-number-asc: "Oplopend" +listing-page-field-date: "Datum" +listing-page-field-title: "Titel" +listing-page-field-description: "Beschrijving" +listing-page-field-author: "Auteur" +listing-page-field-filename: "Bestandsnaam" +listing-page-field-filemodified: "Gewijzigd" +listing-page-field-subtitle: "Subtitel" +listing-page-field-readingtime: "Leestijd" +listing-page-field-categories: "Categorieën" +listing-page-minutes-compact: "{0} min" +listing-page-category-all: "Alle" +listing-page-no-matches: "Geen overeenkomsten" +listing-page-field-wordcount: "Woordentelling" +listing-page-words: "{0} woorden" +listing-page-filter: "Filter" + +draft: "Ontwerp" diff --git a/resources/language/_language-nn.yml b/resources/language/_language-nn.yml new file mode 100644 index 000000000..24293a3b5 --- /dev/null +++ b/resources/language/_language-nn.yml @@ -0,0 +1,127 @@ +toc-title-document: "Innhald" +toc-title-website: "På denne sida" + +related-formats-title: "Andre format" +related-notebooks-title: "Notatbøker" +source-notebooks-prefix: "Kjelde" +other-links-title: "Andre lenker" +code-links-title: "Kodelenker" +launch-dev-container-title: "Start Dev Container" +launch-binder-title: "Start Binder" + +article-notebook-label: "Artikkelnotatbok" +notebook-preview-download: "Last ned notatbok" +notebook-preview-download-src: "Last ned kjeldekode" +notebook-preview-back: "Tilbake til artikkel" +manuscript-meca-bundle: "MECA-arkiv" + +section-title-abstract: "Samandrag" +section-title-appendices: "Vedlegg" +section-title-footnotes: "Fotnotar" +section-title-references: "Referansar" +section-title-reuse: "Bruk omatt" +section-title-copyright: "Opphavsrett" +section-title-citation: "Sitat" + +appendix-attribution-cite-as: "Siter dette arbeidet som:" +appendix-attribution-bibtex: "BibTeX-sitering:" +appendix-view-license: "Vis Lisens" + +title-block-author-single: "Forfattar" +title-block-author-plural: "Forfattarar" +title-block-affiliation-single: "Tilknyting" +title-block-affiliation-plural: "Tilknytingar" +title-block-published: "Publisert" +title-block-modified: "Endra" +title-block-keywords: "Nøkkelord" + +callout-tip-title: "Tips" +callout-note-title: "Obs" +callout-warning-title: "Advarsel" +callout-important-title: "Viktig" +callout-caution-title: "Pass på" + +code-summary: "Kode" + +code-tools-menu-caption: "Kode" +code-tools-show-all-code: "Vis heile koden" +code-tools-hide-all-code: "Skjul heile koden" +code-tools-view-source: "Sjå kjelde" +code-tools-source-code: "Kjeldekode" + +code-line: "Linje" +code-lines: "Linjer" + +copy-button-tooltip: "Kopier til utklippstavla" +copy-button-tooltip-success: "Kopiert!" + +repo-action-links-edit: "Endre denne sida" +repo-action-links-source: "Vis kjelde" +repo-action-links-issue: "Meld inn problem" + +back-to-top: "Til toppen" + +search-no-results-text: "Ingen treff" +search-matching-documents-text: "passande dokument" +search-copy-link-title: "Kopier lenke til søk" +search-hide-matches-text: "Skjul resterande treff" +search-more-match-text: "treff til i dokumentet" +search-more-matches-text: "fleire treff i dokumentet" +search-clear-button-title: "Tøm" +search-text-placeholder: "" +search-detached-cancel-button-title: "Avbryt" +search-submit-button-title: "Send inn" +search-label: "Søk" + +toggle-section: "Bytt avsnitt" +toggle-sidebar: "Bytt sidestolpe" +toggle-dark-mode: "Mørk modus" +toggle-reader-mode: "Bytt lesemodus" +toggle-navigation: "Bytt navigasjon" + +crossref-fig-title: "Figur" +crossref-tbl-title: "Tabell" +crossref-lst-title: "Liste" +crossref-thm-title: "Teorem" +crossref-lem-title: "Lemma" +crossref-cor-title: "Korollar" +crossref-prp-title: "Erklæring" +crossref-cnj-title: "Formodning" +crossref-def-title: "Definisjon" +crossref-exm-title: "Døme" +crossref-exr-title: "Oppgåve" +crossref-ch-prefix: "Kapittel" +crossref-apx-prefix: "Vedlegg" +crossref-sec-prefix: "Avsnitt" +crossref-eq-prefix: "Likning" +crossref-lof-title: "Figurliste" +crossref-lot-title: "Tabelliste" +crossref-lol-title: "Listeoversikt" + +environment-proof-title: "Bevis" +environment-remark-title: "Merknad" +environment-solution-title: "Løysing" + +listing-page-order-by: "Sorter etter" +listing-page-order-by-default: "Standard" +listing-page-order-by-date-asc: "Eldst" +listing-page-order-by-date-desc: "Nyast" +listing-page-order-by-number-desc: "Høg til låg" +listing-page-order-by-number-asc: "Låg til høg" +listing-page-field-date: "Dato" +listing-page-field-title: "Tittel" +listing-page-field-description: "Skildring" +listing-page-field-author: "Forfattar" +listing-page-field-filename: "Filnamn" +listing-page-field-filemodified: "Endra" +listing-page-field-subtitle: "Underoverskrift" +listing-page-field-readingtime: "Lesetid" +listing-page-field-categories: "Kategoriar" +listing-page-minutes-compact: "{0} min." +listing-page-category-all: "Alle" +listing-page-no-matches: "Ingen passande treff" +listing-page-field-wordcount: "Ordteljing" +listing-page-words: "{0} ord" +listing-page-filter: "Filter" + +draft: "Utkast" diff --git a/resources/language/_language-pl.yml b/resources/language/_language-pl.yml new file mode 100644 index 000000000..acb46c0ba --- /dev/null +++ b/resources/language/_language-pl.yml @@ -0,0 +1,127 @@ +toc-title-document: "Spis treści" +toc-title-website: "Na tej stronie" + +related-formats-title: "Inne formaty" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "Źródło" +other-links-title: "Inne odnośniki" +code-links-title: "Linki do kodu" +launch-dev-container-title: "Uruchom Dev Container" +launch-binder-title: "Uruchom Binder" + +article-notebook-label: "Notatnik artykułu" +notebook-preview-download: "Pobierz notatnik" +notebook-preview-download-src: "Pobierz kod źródłowy" +notebook-preview-back: "Powrót do artykułu" +manuscript-meca-bundle: "Archiwum MECA" + +section-title-abstract: "Abstrakt" +section-title-appendices: "Załączniki" +section-title-footnotes: "Przypisy" +section-title-references: "Bibliografia" +section-title-reuse: "Licencja" +section-title-copyright: "Prawa autorskie" +section-title-citation: "Cytowanie" + +appendix-attribution-cite-as: "W celu atrybucji, proszę cytować tę pracę jako:" +appendix-attribution-bibtex: "cytowanie BibTeX:" +appendix-view-license: "Pokaż Licencję" + +title-block-author-single: "Autor" +title-block-author-plural: "Autorzy" +title-block-affiliation-single: "Afiliacja" +title-block-affiliation-plural: "Afiliacje" +title-block-published: "Opublikowano" +title-block-modified: "Zmodyfikowano" +title-block-keywords: "Słowa kluczowe" + +callout-tip-title: "Wskazówka" +callout-note-title: "Adnotacja" +callout-warning-title: "Ostrzeżenie" +callout-important-title: "Ważne" +callout-caution-title: "Zagrożenie" + +code-summary: "Kod" + +code-line: "Linia" +code-lines: "Linie" + +code-tools-menu-caption: "Kod" +code-tools-show-all-code: "Pokaż cały kod" +code-tools-hide-all-code: "Ukryj cały kod" +code-tools-view-source: "Pokaż źródło" +code-tools-source-code: "Kod źródłowy" + +copy-button-tooltip: "Kopiuj do schowka" +copy-button-tooltip-success: "Skopiowano!" + +repo-action-links-edit: "Edytuj tę stronę" +repo-action-links-source: "Pokaż źródło" +repo-action-links-issue: "Zgłoś problem" + +back-to-top: "Powrót do góry" + +search-no-results-text: "Brak wyników" +search-matching-documents-text: "dopasowane dokumenty" +search-copy-link-title: "Kopiuj link do wyszukiwania" +search-hide-matches-text: "Ukryj dodatkowe dopasowania" +search-more-match-text: "więcej dopasowań w tym dokumencie" +search-more-matches-text: "więcej dopasowań w tym dokumencie" +search-clear-button-title: "Wyczyść" +search-text-placeholder: "" +search-detached-cancel-button-title: "Anuluj" +search-submit-button-title: "Zatwierdź" +search-label: "Szukaj" + +toggle-section: "Przełącz sekcję" +toggle-sidebar: "Przełącz pasek boczny" +toggle-dark-mode: "Przełącz tryb ciemny" +toggle-reader-mode: "Przełącz tryb czytnika" +toggle-navigation: "Przełącz nawigację" + +crossref-fig-title: "Rysunek" +crossref-tbl-title: "Tabela" +crossref-lst-title: "Wykaz" +crossref-thm-title: "Twierdzenie" +crossref-lem-title: "Lemat" +crossref-cor-title: "Wniosek" +crossref-prp-title: "Proposition" +crossref-cnj-title: "Przypuszczenie" +crossref-def-title: "Definicja" +crossref-exm-title: "Przykład" +crossref-exr-title: "Ćwiczenie" +crossref-ch-prefix: "Rozdział" +crossref-apx-prefix: "Załącznik" +crossref-sec-prefix: "Sekcja" +crossref-eq-prefix: "Równanie" +crossref-lof-title: "Spis rycin" +crossref-lot-title: "Spis tabel" +crossref-lol-title: "Spis wykazów" + +environment-proof-title: "Dowód" +environment-remark-title: "Komentarz" +environment-solution-title: "Rozwiązanie" + +listing-page-order-by: "Sortuj według" +listing-page-order-by-default: "Domyślnie" +listing-page-order-by-date-asc: "Od najstarszych" +listing-page-order-by-date-desc: "Od najnowszych" +listing-page-order-by-number-desc: "Od największych" +listing-page-order-by-number-asc: "Od najmniejszych" +listing-page-field-date: "Data" +listing-page-field-title: "Tytuł" +listing-page-field-description: "Opis" +listing-page-field-author: "Autor" +listing-page-field-filename: "Nazwa pliku" +listing-page-field-filemodified: "Zmodyfikowano" +listing-page-field-subtitle: "Podtytuł" +listing-page-field-readingtime: "Czas czytania" +listing-page-field-categories: "Kategorie" +listing-page-minutes-compact: "{0} min" +listing-page-category-all: "Wszystkie" +listing-page-no-matches: "Brak pasujących" +listing-page-field-wordcount: "Licznik Słów" +listing-page-words: "{0} słów" +listing-page-filter: "Filtr" + +draft: "Projekt" diff --git a/resources/language/_language-pt-BR.yml b/resources/language/_language-pt-BR.yml new file mode 100644 index 000000000..e675ad46f --- /dev/null +++ b/resources/language/_language-pt-BR.yml @@ -0,0 +1,127 @@ +toc-title-document: "Índice" +toc-title-website: "Nesta página" + +related-formats-title: "Outros formatos" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "Fonte" +other-links-title: "Outros Links" +code-links-title: "Links de código" +launch-dev-container-title: "Iniciar Dev Container" +launch-binder-title: "Iniciar Binder" + +article-notebook-label: "Caderno de Artigo" +notebook-preview-download: "Baixar Caderno" +notebook-preview-download-src: "Baixar código-fonte" +notebook-preview-back: "Voltar ao Artigo" +manuscript-meca-bundle: "Arquivo MECA" + +section-title-abstract: "Resumo" +section-title-appendices: "Apêndices" +section-title-footnotes: "Notas de rodapé" +section-title-references: "Referências" +section-title-reuse: "Reuso" +section-title-copyright: "Direito autoral" +section-title-citation: "Citação" + +appendix-attribution-bibtex: "BibTeX" +appendix-attribution-cite-as: "Por favor, cite este trabalho como:" +appendix-view-license: "Visualizar Licença" + +title-block-author-single: "Autor" +title-block-author-plural: "Autores" +title-block-affiliation-single: "Afiliação" +title-block-affiliation-plural: "Afiliações" +title-block-published: "Data de Publicação" +title-block-keywords: "Palavras-chave" + +callout-tip-title: "Dica" +callout-note-title: "Nota" +callout-warning-title: "Aviso" +callout-important-title: "Importante" +callout-caution-title: "Cuidado" + +code-summary: "Código" + +code-line: "Linha" +code-lines: "Linhas" + +code-tools-menu-caption: "Código" +code-tools-show-all-code: "Mostrar o código" +code-tools-hide-all-code: "Esconder o código" +code-tools-view-source: "Ver o código fonte" +code-tools-source-code: "Código fonte" + +tools-share: "Compartilhar" +tools-download: "Baixar" + +copy-button-tooltip: "Copiar para a área de transferência" +copy-button-tooltip-success: "Copiada" + +repo-action-links-edit: "Editar essa página" +repo-action-links-source: "Ver o código fonte" +repo-action-links-issue: "Criar uma issue" + +back-to-top: "De volta ao topo" + +search-no-results-text: "Nenhum resultado" +search-matching-documents-text: "documentos correspondentes" +search-copy-link-title: "Copiar link para a busca" +search-hide-matches-text: "Esconder correspondências adicionais" +search-more-match-text: "mais correspondência neste documento" +search-more-matches-text: "mais correspondências neste documento" +search-clear-button-title: "Limpar" +search-text-placeholder: "" +search-detached-cancel-button-title: "Cancelar" +search-submit-button-title: "Enviar" +search-label: "Procurar" + +toggle-section: "Alternar seção" +toggle-sidebar: "Alternar barra lateral" +toggle-dark-mode: "Alternar modo escuro" +toggle-reader-mode: "Alternar modo de leitor" +toggle-navigation: "Alternar de navegação" + +crossref-fig-title: "Figura" +crossref-tbl-title: "Tabela" +crossref-lst-title: "Listagem" +crossref-thm-title: "Teorema" +crossref-lem-title: "Lema" +crossref-cor-title: "Corolário" +crossref-prp-title: "Proposição" +crossref-cnj-title: "Conjectura" +crossref-def-title: "Definição" +crossref-exm-title: "Exemplo" +crossref-exr-title: "Exercício" +crossref-sec-prefix: "Seção" +crossref-eq-prefix: "Equação" +crossref-lof-title: "Lista de Figuras" +crossref-lot-title: "Lista de Tabelas" +crossref-lol-title: "Lista de Listagens" + +environment-proof-title: "Comprovação" +environment-remark-title: "Comentário" +environment-solution-title: "Solução" + +listing-page-order-by: "Ordenar por" +listing-page-order-by-default: "Padrão" +listing-page-order-by-date-asc: "Mais antigo" +listing-page-order-by-date-desc: "O mais novo" +listing-page-order-by-number-desc: "Decrescente" +listing-page-order-by-number-asc: "Baixo para alto" +listing-page-field-date: "Data" +listing-page-field-title: "Título" +listing-page-field-description: "Descrição" +listing-page-field-author: "Autor" +listing-page-field-filename: "Nome do arquivo" +listing-page-field-filemodified: "Modificada" +listing-page-field-subtitle: "Legenda" +listing-page-field-readingtime: "Tempo de leitura" +listing-page-field-wordcount: "Contagem de palavras" +listing-page-field-categories: "Categorias" +listing-page-minutes-compact: "{0}Min" +listing-page-category-all: "Todos" +listing-page-no-matches: "Sem itens correspondentes" +listing-page-words: "{0} palavras" +listing-page-filter: "Filtro" + +draft: "Rascunho" diff --git a/resources/language/_language-pt.yml b/resources/language/_language-pt.yml new file mode 100644 index 000000000..250e5b2ba --- /dev/null +++ b/resources/language/_language-pt.yml @@ -0,0 +1,127 @@ +toc-title-document: "Índice" +toc-title-website: "Nesta página" + +related-formats-title: "Outros formatos" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "Fonte" +other-links-title: "Outros Links" +code-links-title: "Ligações de código" +launch-dev-container-title: "Iniciar Dev Container" +launch-binder-title: "Iniciar Binder" + +article-notebook-label: "Caderno do Artigo" +notebook-preview-download: "Baixar Caderno" +notebook-preview-download-src: "Descarregar código fonte" +notebook-preview-back: "Voltar ao Artigo" +manuscript-meca-bundle: "Arquivo MECA" + +section-title-abstract: "Resumo" +section-title-appendices: "Apêndices" +section-title-footnotes: "Notas de rodapé" +section-title-references: "Referências" +section-title-reuse: "Reuso" +section-title-copyright: "Direito autoral" +section-title-citation: "Citação" + +appendix-attribution-bibtex: "BibTeX" +appendix-attribution-cite-as: "Por favor, cite este trabalho como:" +appendix-view-license: "Ver Licença" + +title-block-author-single: "Autor" +title-block-author-plural: "Autores" +title-block-affiliation-single: "Afiliação" +title-block-affiliation-plural: "Afiliações" +title-block-published: "Data de Publicação" +title-block-modified: "Data de Modificação" +title-block-keywords: "Palavras-chave" + +callout-tip-title: "Dica" +callout-note-title: "Nota" +callout-warning-title: "Aviso" +callout-important-title: "Importante" +callout-caution-title: "Cuidado" + +code-summary: "Código" + +code-line: "Linha" +code-lines: "Linhas" + +code-tools-menu-caption: "Código" +code-tools-show-all-code: "Mostrar o código" +code-tools-hide-all-code: "Esconder o código" +code-tools-view-source: "Ver o código fonte" +code-tools-source-code: "Código fonte" + +copy-button-tooltip: "Copiar para a área de transferência" +copy-button-tooltip-success: "Copiada" + +repo-action-links-edit: "Editar essa página" +repo-action-links-source: "Ver o código fonte" +repo-action-links-issue: "Criar uma issue" + +back-to-top: "De volta ao topo" + +search-no-results-text: "Nenhum resultado" +search-matching-documents-text: "documentos correspondentes" +search-copy-link-title: "Copiar link para a busca" +search-hide-matches-text: "Esconder correspondências adicionais" +search-more-match-text: "mais correspondência neste documento" +search-more-matches-text: "mais correspondências neste documento" +search-clear-button-title: "Limpar" +search-text-placeholder: "" +search-detached-cancel-button-title: "Cancelar" +search-submit-button-title: "Enviar" +search-label: "Procurar" + +toggle-section: "Alternar seção" +toggle-sidebar: "Alternar barra lateral" +toggle-dark-mode: "Alternar modo escuro" +toggle-reader-mode: "Alternar modo de leitor" +toggle-navigation: "Alternar de navegação" + +crossref-fig-title: "Figura" +crossref-tbl-title: "Tabela" +crossref-lst-title: "Listagem" +crossref-thm-title: "Teorema" +crossref-lem-title: "Lema" +crossref-cor-title: "Corolário" +crossref-prp-title: "Proposição" +crossref-cnj-title: "Conjetura" +crossref-def-title: "Definição" +crossref-exm-title: "Exemplo" +crossref-exr-title: "Exercício" +crossref-ch-prefix: "Capítulo" +crossref-apx-prefix: "Apêndice" +crossref-sec-prefix: "Seção" +crossref-eq-prefix: "Equação" +crossref-lof-title: "Lista de Figuras" +crossref-lot-title: "Lista de Tabelas" +crossref-lol-title: "Lista de Listagens" + +environment-proof-title: "Comprovação" +environment-remark-title: "Comentário" +environment-solution-title: "Solução" + +listing-page-order-by: "Ordenar por" +listing-page-order-by-default: "Pré-selecionado" +listing-page-order-by-date-asc: "Mais velho" +listing-page-order-by-date-desc: "O mais novo" +listing-page-order-by-number-desc: "Decrescente" +listing-page-order-by-number-asc: "Crescente" +listing-page-field-date: "Data" +listing-page-field-title: "Título" +listing-page-field-description: "Descrição" +listing-page-field-author: "Autor" +listing-page-field-filename: "Nome do arquivo" +listing-page-field-filemodified: "Arquivo modificado" +listing-page-field-subtitle: "Subtítulo" +listing-page-field-readingtime: "Tempo de leitura" +listing-page-field-categories: "Categorias" +listing-page-minutes-compact: "{0} minutos" +listing-page-category-all: "Tudo" +listing-page-no-matches: "Nenhum item correspondente" +listing-page-field-wordcount: "Contagem de Palavras" +listing-page-words: "{0} palavras" +listing-page-filter: "Filtro" + +draft: "Rascunho" diff --git a/resources/language/_language-ru.yml b/resources/language/_language-ru.yml new file mode 100644 index 000000000..70a117d65 --- /dev/null +++ b/resources/language/_language-ru.yml @@ -0,0 +1,127 @@ +toc-title-document: "Содержание" +toc-title-website: "Содержание" + +related-formats-title: "Другие форматы" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "Источник" +other-links-title: "Другие ссылки" +code-links-title: "Ссылки на код" +launch-dev-container-title: "Запустить Dev Container" +launch-binder-title: "Запустить Binder" + +article-notebook-label: "Блокнот статьи" +notebook-preview-download: "Скачать блокнот" +notebook-preview-download-src: "Скачать исходный код" +notebook-preview-back: "Вернуться к статье" +manuscript-meca-bundle: "Архив MECA" + +section-title-abstract: "Аннотация" +section-title-appendices: "Приложения" +section-title-footnotes: "Сноски" +section-title-references: "использованная литература" +section-title-reuse: "Повторное использование" +section-title-copyright: "Авторские права" +section-title-citation: "Цитата" + +appendix-attribution-bibtex: "BibTeX" +appendix-attribution-cite-as: "Пожалуйста, цитируйте эту работу как:" +appendix-view-license: "Просмотреть Лицензию" + +title-block-author-single: "Автор" +title-block-author-plural: "Авторы" +title-block-affiliation-single: "принадлежность" +title-block-affiliation-plural: "Принадлежности" +title-block-published: "Дата публикации" +title-block-modified: "Файл изменен" +title-block-keywords: "Ключевые слова" + +callout-tip-title: "Совет" +callout-note-title: "Уведомление" +callout-warning-title: "Предупреждение" +callout-important-title: "Важное уведомление" +callout-caution-title: "Осторожность" + +code-summary: "Код" + +code-line: "Линия" +code-lines: "Линии" + +code-tools-menu-caption: "Код" +code-tools-show-all-code: "Развернуть код" +code-tools-hide-all-code: "Скрыть код" +code-tools-view-source: "Показать код" +code-tools-source-code: "Исходный код" + +copy-button-tooltip: "Скопировать текст" +copy-button-tooltip-success: "Скопировано" + +repo-action-links-edit: "Редактировать страницу" +repo-action-links-source: "Показать код" +repo-action-links-issue: "Сообщить о проблеме" + +back-to-top: "Наверх" + +search-no-results-text: "Поиск не дал результатов" +search-matching-documents-text: "Результаты поиска" +search-copy-link-title: "Скопировать ссылку" +search-hide-matches-text: "Скрыть дополнительные результаты" +search-more-match-text: "дополнительный результат в этом документе" +search-more-matches-text: "дополнительных результата(-ов) в этом документе" +search-clear-button-title: "Очистить" +search-text-placeholder: "" +search-detached-cancel-button-title: "Отменить" +search-submit-button-title: "Найти" +search-label: "Поиск" + +toggle-section: "Переключить раздел" +toggle-sidebar: "Переключить боковую панель навигации" +toggle-dark-mode: "Переключить темный режим" +toggle-reader-mode: "Переключить режим чтения" +toggle-navigation: "Переключить навигацию" + +crossref-fig-title: "Рисунок" +crossref-tbl-title: "Таблица" +crossref-lst-title: "Список" +crossref-thm-title: "Теорема" +crossref-lem-title: "Лемма" +crossref-cor-title: "Следствие" +crossref-prp-title: "Утверждение" +crossref-cnj-title: "Гипотеза" +crossref-def-title: "Определение" +crossref-exm-title: "Пример" +crossref-exr-title: "Упражнение" +crossref-ch-prefix: "Глава" +crossref-apx-prefix: "Приложение" +crossref-sec-prefix: "Глава" +crossref-eq-prefix: "Уравнение" +crossref-lof-title: "Список Иллюстраций" +crossref-lot-title: "Список Таблиц" +crossref-lol-title: "Список Каталогов" + +environment-proof-title: "Доказательство" +environment-remark-title: "Примечание" +environment-solution-title: "Решение" + +listing-page-order-by: "Сортировать по" +listing-page-order-by-default: "предварительно выбранный" +listing-page-order-by-date-asc: "Самый старый" +listing-page-order-by-date-desc: "Новейшие" +listing-page-order-by-number-desc: "нисходящий" +listing-page-order-by-number-asc: "по возрастанию" +listing-page-field-date: "Дата" +listing-page-field-title: "Заголовок" +listing-page-field-description: "Описание" +listing-page-field-author: "Автор" +listing-page-field-filename: "Имя файла" +listing-page-field-filemodified: "Файл изменен" +listing-page-field-subtitle: "Подзаголовок" +listing-page-field-readingtime: "Время чтения" +listing-page-field-categories: "Категории" +listing-page-minutes-compact: "{0} минут" +listing-page-category-all: "Все" +listing-page-no-matches: "Нет подходящих элементов" +listing-page-field-wordcount: "Подсчет слов" +listing-page-words: "{0} слов" +listing-page-filter: "Фильтр" + +draft: "Черновик" diff --git a/resources/language/_language-sk.yml b/resources/language/_language-sk.yml new file mode 100644 index 000000000..77cde8324 --- /dev/null +++ b/resources/language/_language-sk.yml @@ -0,0 +1,127 @@ +toc-title-document: "Obsah" +toc-title-website: "Na tejto stránke" + +related-formats-title: "Ostatné formáty" +related-notebooks-title: "Notebooky" +source-notebooks-prefix: "Zdroj" +other-links-title: "Ďalšie odkazy" +code-links-title: "Odkazy na kód" +launch-dev-container-title: "Spustiť Dev Container" +launch-binder-title: "Spustiť Binder" + +article-notebook-label: "Poznámkový blok článku" +notebook-preview-download: "Stiahnuť Poznámkový blok" +notebook-preview-download-src: "Stiahnuť zdrojový kód" +notebook-preview-back: "Späť na článok" +manuscript-meca-bundle: "Archív MECA" + +section-title-abstract: "Abstrakt" +section-title-appendices: "Prílohy" +section-title-footnotes: "Poznámky pod čiarou" +section-title-references: "Literatúra" +section-title-reuse: "Pravidlá použitia" +section-title-copyright: "Copyright" +section-title-citation: "Citácia" + +appendix-attribution-cite-as: "Prosím, toto dielo citujte ako:" +appendix-attribution-bibtex: "BibTeX citácia:" +appendix-view-license: "Zobraziť Licenciu" + +title-block-author-single: "Autor" +title-block-author-plural: "Autori" +title-block-affiliation-single: "Príslušnosť" +title-block-affiliation-plural: "Príslušnosť" +title-block-published: "Publikované" +title-block-modified: "Zmenené" +title-block-keywords: "Kľúčové slová" + +callout-tip-title: "Tip" +callout-note-title: "Poznámka" +callout-warning-title: "Varovanie" +callout-important-title: "Dôležité" +callout-caution-title: "Výstraha" + +code-summary: "Kód" + +code-tools-menu-caption: "Kód" +code-tools-show-all-code: "Zobraziť celý kód" +code-tools-hide-all-code: "Skryť celý kód" +code-tools-view-source: "Zobraziť zdrojový kód" +code-tools-source-code: "Zdrojový kód" + +code-line: "Riadok" +code-lines: "Riadky" + +copy-button-tooltip: "Kopírovať do schránky" +copy-button-tooltip-success: "Skopírované!" + +repo-action-links-edit: "Editovať túto stranu" +repo-action-links-source: "Zobraziť zdroj" +repo-action-links-issue: "Nahlásiť problém" + +back-to-top: "Nazad nahor" + +search-no-results-text: "Žiadne výsledky" +search-matching-documents-text: "zhodné dokumenty" +search-copy-link-title: "Skopírovať odkaz pre vyhľadávanie" +search-hide-matches-text: "Skryť ďalšie výsledky" +search-more-match-text: "ďalší výsledok v tomto dokumente" +search-more-matches-text: "ďalších výsledkov v tomto dokumente" +search-clear-button-title: "Vymazať" +search-text-placeholder: "" +search-detached-cancel-button-title: "Zrušiť" +search-submit-button-title: "Odoslať" +search-label: "Hľadať" + +toggle-section: "Prepnúť sekciu" +toggle-sidebar: "Prepnúť postrannú navigáciu" +toggle-dark-mode: "Prepnúť tmavý režim" +toggle-reader-mode: "Prepnúť režim čítania" +toggle-navigation: "Prepnúť navigáciu" + +crossref-fig-title: "Obrázok" +crossref-tbl-title: "Tabuľka" +crossref-lst-title: "Výpis" +crossref-thm-title: "Teorém" +crossref-lem-title: "Lemma" +crossref-cor-title: "Dôsledok" +crossref-prp-title: "Tvrdenie" +crossref-cnj-title: "Domnienka" +crossref-def-title: "Definícia" +crossref-exm-title: "Príklad" +crossref-exr-title: "Cvičenie" +crossref-ch-prefix: "Kapitola" +crossref-apx-prefix: "Príloha" +crossref-sec-prefix: "Sekcia" +crossref-eq-prefix: "Rovnica" +crossref-lof-title: "Zoznam obrázkov" +crossref-lot-title: "Zoznam tabuliek" +crossref-lol-title: "Zoznam výpisov" + +environment-proof-title: "Dôkaz" +environment-remark-title: "Poznámka" +environment-solution-title: "Riešenie" + +listing-page-order-by: "Zoradiť podľa" +listing-page-order-by-default: "Prednastavené" +listing-page-order-by-date-asc: "Najstaršie" +listing-page-order-by-date-desc: "Najnovšie" +listing-page-order-by-number-desc: "Od najvyššieho po najnižšie" +listing-page-order-by-number-asc: "Od najnižšieho po najvyššie" +listing-page-field-date: "Dátum" +listing-page-field-title: "Názov" +listing-page-field-description: "Popis" +listing-page-field-author: "Autor" +listing-page-field-filename: "Názov súboru" +listing-page-field-filemodified: "Upravené" +listing-page-field-subtitle: "Podtitul" +listing-page-field-readingtime: "Doba čítania" +listing-page-field-categories: "Kategórie" +listing-page-minutes-compact: "{0} minút" +listing-page-category-all: "Všetko" +listing-page-no-matches: "Žiadne nájdené výsledky" +listing-page-field-wordcount: "Počet slov" +listing-page-words: "{0} slov" +listing-page-filter: "Filter" + +draft: "Návrh" diff --git a/resources/language/_language-sl.yml b/resources/language/_language-sl.yml new file mode 100644 index 000000000..7862f8119 --- /dev/null +++ b/resources/language/_language-sl.yml @@ -0,0 +1,131 @@ +toc-title-document: "Kazalo vsebine" +toc-title-website: "Na tej strani" + +related-formats-title: "Drugi formati" +related-notebooks-title: "Zvezki" +source-notebooks-prefix: "Vir" +other-links-title: "Druge povezave" +code-links-title: "Povezave do kode" +launch-dev-container-title: "Zaženi razvojni kontejner" +launch-binder-title: "Zaženi Binder" + +article-notebook-label: "Zvezek članka" +notebook-preview-download: "Prenesi zvezek" +notebook-preview-download-src: "Prenesi vir" +notebook-preview-back: "Nazaj na članek" +manuscript-meca-bundle: "MECA paket" + +section-title-abstract: "Povzetek" +section-title-appendices: "Priloge" +section-title-footnotes: "Opombe" +section-title-references: "Viri" +section-title-reuse: "Ponovna uporaba" +section-title-copyright: "Avtorske pravice" +section-title-citation: "Citiranje" + +appendix-attribution-cite-as: "Za navedbo prosimo, citirajte to delo kot:" +appendix-attribution-bibtex: "BibTeX citat:" +appendix-view-license: "Ogled licence" + +title-block-author-single: "Avtor" +title-block-author-plural: "Avtorji" +title-block-affiliation-single: "Pripadnost" +title-block-affiliation-plural: "Pripadnosti" +title-block-published: "Objavljeno" +title-block-modified: "Spremenjeno" +title-block-keywords: "Ključne besede" + +callout-tip-title: "Nasvet" +callout-note-title: "Opomba" +callout-warning-title: "Opozorilo" +callout-important-title: "Pomembno" +callout-caution-title: "Pozor" + +code-summary: "Koda" + +code-tools-menu-caption: "Koda" +code-tools-show-all-code: "Prikaži vso kodo" +code-tools-hide-all-code: "Skrij vso kodo" +code-tools-view-source: "Ogled vira" +code-tools-source-code: "Izvorna koda" + +tools-share: "Deli" +tools-download: "Prenesi" + +code-line: "Vrstica" +code-lines: "Vrstice" + +copy-button-tooltip: "Kopiraj v odložišče" +copy-button-tooltip-success: "Kopirano!" + +repo-action-links-edit: "Uredi to stran" +repo-action-links-source: "Ogled vira" +repo-action-links-issue: "Poročaj o težavi" + +back-to-top: "Nazaj na vrh" + +search-no-results-text: "Ni rezultatov" +search-matching-documents-text: "ujemajoči se dokumenti" +search-copy-link-title: "Kopiraj povezavo do iskanja" +search-hide-matches-text: "Skrij dodatne zadetke" +search-more-match-text: "več zadetkov v tem dokumentu" +search-more-matches-text: "več zadetkov v tem dokumentu" +search-clear-button-title: "Počisti" +search-text-placeholder: "" +search-detached-cancel-button-title: "Prekliči" +search-submit-button-title: "Pošlji" +search-label: "Iskanje" + +toggle-section: "Preklopi odsek" +toggle-sidebar: "Preklopi navigacijo v stranski vrstici" +toggle-dark-mode: "Preklopi temni način" +toggle-reader-mode: "Preklopi način za branje" +toggle-navigation: "Preklopi navigacijo" + + +crossref-fig-title: "Slika" +crossref-tbl-title: "Tabela" +crossref-lst-title: "Seznam" +crossref-thm-title: "Izrek" +crossref-lem-title: "Lema" +crossref-cor-title: "Posledica" +crossref-prp-title: "Predlog" +crossref-cnj-title: "Domneva" +crossref-def-title: "Definicija" +crossref-exm-title: "Primer" +crossref-exr-title: "Naloga" +crossref-ch-prefix: "Poglavje" +crossref-apx-prefix: "Priloga" +crossref-sec-prefix: "Odsek" +crossref-eq-prefix: "Enakost" +crossref-lof-title: "Seznam slik" +crossref-lot-title: "Seznam tabel" +crossref-lol-title: "Seznam seznamov" + +environment-proof-title: "Dokaz" +environment-remark-title: "Opomba" +environment-solution-title: "Rešitev" + +listing-page-order-by: "Razvrsti po" +listing-page-order-by-default: "Privzeto" +listing-page-order-by-date-asc: "Najstarejši" +listing-page-order-by-date-desc: "Najnovejši" +listing-page-order-by-number-desc: "Od največjega do najmanjšega" +listing-page-order-by-number-asc: "Od najmanjšega do največjega" +listing-page-field-date: "Datum" +listing-page-field-title: "Naslov" +listing-page-field-description: "Opis" +listing-page-field-author: "Avtor" +listing-page-field-filename: "Ime datoteke" +listing-page-field-filemodified: "Spremenjeno" +listing-page-field-subtitle: "Podnaslov" +listing-page-field-readingtime: "Čas branja" +listing-page-field-wordcount: "Število besed" +listing-page-field-categories: "Kategorije" +listing-page-minutes-compact: "{0} min" +listing-page-category-all: "Vse" +listing-page-no-matches: "Ni ustreznih elementov" +listing-page-words: "{0} besed" +listing-page-filter: "Filtriraj" + +draft: "Osnutek" diff --git a/resources/language/_language-sr-Latn.yml b/resources/language/_language-sr-Latn.yml new file mode 100644 index 000000000..5935111b9 --- /dev/null +++ b/resources/language/_language-sr-Latn.yml @@ -0,0 +1,122 @@ +toc-title-document: "Sadržaj" +toc-title-website: "Na ovoj stranici" + +related-formats-title: "Drugi Formati" +related-notebooks-title: "Sveske" +source-notebooks-prefix: "Izvor" +other-links-title: "Drugi Linkovi" + +article-notebook-label: "Sveska Članka" +notebook-preview-download: "Skini Svesku" +notebook-preview-download-src: "Skini Izvor" +notebook-preview-back: "Nazad na Članak" +manuscript-meca-bundle: "MECA Paket" + +section-title-abstract: "Apstrakt" +section-title-appendices: "Apendiks" +section-title-footnotes: "Fusnota" +section-title-references: "Reference" +section-title-reuse: "Iskoristi Ponovo" +section-title-copyright: "Autorska Prava" +section-title-citation: "Navođenje" + +appendix-attribution-cite-as: "Za pripisivanje autoru, molimo navedite ovaj rad sa:" +appendix-attribution-bibtex: "BibTeX navođenje:" +appendix-view-license: "Pogledaj Licencu" + +title-block-author-single: "Autor" +title-block-author-plural: "Autori" +title-block-affiliation-single: "Afilijacija" +title-block-affiliation-plural: "Afilijacije" +title-block-published: "Objavljeno" +title-block-modified: "Izmenjeno" +title-block-keywords: "Ključne Reči" + +callout-tip-title: "Savet" +callout-note-title: "Beleška" +callout-warning-title: "Upozorenje" +callout-important-title: "Bitno" +callout-caution-title: "Pažnja" + +code-summary: "Kod" + +code-tools-menu-caption: "Kod" +code-tools-show-all-code: "Prikaži Sav Kod" +code-tools-hide-all-code: "Sakrij Sav Kod" +code-tools-view-source: "Prikaži Izvor" +code-tools-source-code: "Izvorni Kod" + +code-line: "Red" +code-lines: "Redovi" + +copy-button-tooltip: "Kopiraj" +copy-button-tooltip-success: "Kopirano!" + +repo-action-links-edit: "Izmeni ovu stranicu" +repo-action-links-source: "Prikaži izvor" +repo-action-links-issue: "Prijavi grešku" + +back-to-top: "Nazad na vrh" + +search-no-results-text: "Nema rezultata" +search-matching-documents-text: "slična dokumenta" +search-copy-link-title: "Kopiraj link za pretraživanje" +search-hide-matches-text: "Sakrij dodatne rezultate" +search-more-match-text: "još rezultat u ovom dokumentu" +search-more-matches-text: "još rezultata u ovom dokumentu" +search-clear-button-title: "Obriši" +search-text-placeholder: "" +search-detached-cancel-button-title: "Odustani" +search-submit-button-title: "Predaj" +search-label: "Pretraži" + +toggle-section: "Prekidač za odeljak" +toggle-sidebar: "Prekidač za navigaciju" +toggle-dark-mode: "Prekidač za tamnu temu" +toggle-reader-mode: "Prekirač za mod čitanja" +toggle-navigation: "Prekidač navigacije" + +crossref-fig-title: "Figura" +crossref-tbl-title: "Tabela" +crossref-lst-title: "Lista" +crossref-thm-title: "Teorema" +crossref-lem-title: "Lema" +crossref-cor-title: "Korolarija" +crossref-prp-title: "Propozicija" +crossref-cnj-title: "Hipoteza" +crossref-def-title: "Definicija" +crossref-exm-title: "Primer" +crossref-exr-title: "Zadatak" +crossref-ch-prefix: "Poglavlje" +crossref-apx-prefix: "Apendiks" +crossref-sec-prefix: "Odeljak" +crossref-eq-prefix: "Jednačina" +crossref-lof-title: "Lista Figura" +crossref-lot-title: "Lista Tabela" +crossref-lol-title: "Spisak lista" + +environment-proof-title: "Dokaz" +environment-remark-title: "Napomena" +environment-solution-title: "Rešenje" + +listing-page-order-by: "Poređaj Po" +listing-page-order-by-default: "Standardno" +listing-page-order-by-date-asc: "Najstarije" +listing-page-order-by-date-desc: "Najnovije" +listing-page-order-by-number-desc: "Najviše do Najniže" +listing-page-order-by-number-asc: "Najniže do Najviše" +listing-page-field-date: "Datum" +listing-page-field-title: "Naslov" +listing-page-field-description: "Sažetak" +listing-page-field-author: "Autor" +listing-page-field-filename: "Ime Datoteke" +listing-page-field-filemodified: "Izmenjeno" +listing-page-field-subtitle: "Podnaslov" +listing-page-field-readingtime: "Potrebno za čitanje" +listing-page-field-categories: "Kategorije" +listing-page-minutes-compact: "{0} min" +listing-page-category-all: "Sve" +listing-page-no-matches: "Slična dokumenta nisu pronađena" +listing-page-filter: "Filter" + +draft: "Nacrt" diff --git a/resources/language/_language-sv.yml b/resources/language/_language-sv.yml new file mode 100644 index 000000000..d34e630f0 --- /dev/null +++ b/resources/language/_language-sv.yml @@ -0,0 +1,127 @@ +toc-title-document: "Innehållsförteckning" +toc-title-website: "På denna sida" + +related-formats-title: "Andra Format" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "Källa" +other-links-title: "Övriga länkar" +code-links-title: "Kodlänkar" +launch-dev-container-title: "Starta Dev Container" +launch-binder-title: "Starta Binder" + +article-notebook-label: "Artikelanteckningsbok" +notebook-preview-download: "Ladda ner anteckningsbok" +notebook-preview-download-src: "Ladda ner källkod" +notebook-preview-back: "Tillbaka till artikel" +manuscript-meca-bundle: "MECA-arkiv" + +section-title-abstract: "Sammanfattning" +section-title-appendices: "Bilagor" +section-title-footnotes: "Fotnot" +section-title-references: "Referenser" +section-title-reuse: "Återanvänd" +section-title-copyright: "Copyright" +section-title-citation: "Citat" + +appendix-attribution-cite-as: "Hänvisa till detta arbete som:" +appendix-attribution-bibtex: "BibTeX hänvisning:" +appendix-view-license: "Visa Licens" + +title-block-author-single: "Författare" +title-block-author-plural: "Författare" +title-block-affiliation-single: "Anknuten" +title-block-affiliation-plural: "Anknutna" +title-block-published: "Utgiven" +title-block-modified: "Ändrad" +title-block-keywords: "Nyckelord" + +callout-tip-title: "Tips" +callout-note-title: "Notera" +callout-warning-title: "Varning" +callout-important-title: "Viktigt" +callout-danger-title: "Försiktigt" + +code-summary: "Kod" + +code-tools-menu-caption: "Kod" +code-tools-show-all-code: "Visa all kod" +code-tools-hide-all-code: "Göm all kod" +code-tools-view-source: "Visa källa" +code-tools-source-code: "Källkod" + +code-line: "Rad" +code-lines: "Rader" + +copy-button-tooltip: "Kopiera till urklipp" +copy-button-tooltip-success: "Kopierat!" + +repo-action-links-edit: "Redigera denna sida" +repo-action-links-source: "Visa källa" +repo-action-links-issue: "Rapportera ett problem" + +back-to-top: "Tillbaka till toppen" + +search-no-results-text: "Inget resultat" +search-matching-documents-text: "matchande dokument" +search-copy-link-title: "Kopiera länk för att söka" +search-hide-matches-text: "Göm ytterligare resultat" +search-more-match-text: "annat resultat i detta dokument" +search-more-matches-text: "fler resultat i detta dokument" +search-clear-button-title: "Rensa" +search-text-placeholder: "" +search-detached-cancel-button-title: "Avbryt" +search-submit-button-title: "Verkställ" +search-label: "Sök" + +toggle-section: "Skifta sektion" +toggle-sidebar: "Skifta sidonavigering" +toggle-dark-mode: "Skifta mörkt läge" +toggle-reader-mode: "Skifta läsläge" +toggle-navigation: "Skifta navigering" + +crossref-fig-title: "Figur" +crossref-tbl-title: "Tabell" +crossref-lst-title: "Lista" +crossref-thm-title: "Teorem" +crossref-lem-title: "Lemma" +crossref-cor-title: "Följdsats" +crossref-prp-title: "Påstående" +crossref-cnj-title: "Förmodan" +crossref-def-title: "Definition" +crossref-exm-title: "Exempel" +crossref-exr-title: "Uppgift" +crossref-ch-prefix: "Kapitel" +crossref-apx-prefix: "Bilaga" +crossref-sec-prefix: "Avsnitt" +crossref-eq-prefix: "Ekvation" +crossref-lof-title: "Figurförteckning" +crossref-lot-title: "Tabellförteckning" +crossref-lol-title: "Listförteckning" + +environment-proof-title: "Bevis" +environment-remark-title: "Anmärkning" +environment-solution-title: "Lösning" + +listing-page-order-by: "Sorterat efter" +listing-page-order-by-default: "Standard" +listing-page-order-by-date-asc: "Äldst" +listing-page-order-by-date-desc: "Nyast" +listing-page-order-by-number-desc: "Högt till lågt" +listing-page-order-by-number-asc: "Lågt till högt" +listing-page-field-date: "Datum" +listing-page-field-title: "Titel" +listing-page-field-description: "Beskrivning" +listing-page-field-author: "Författare" +listing-page-field-filename: "Filnamn" +listing-page-field-filemodified: "Ändrad" +listing-page-field-subtitle: "Undertitel" +listing-page-field-readingtime: "Lästid" +listing-page-field-categories: "Kategorier" +listing-page-minutes-compact: "{0} min" +listing-page-category-all: "Allt" +listing-page-no-matches: "Inget resultat" +listing-page-field-wordcount: "Ordmätning" +listing-page-words: "{0} ord" +listing-page-filter: "Filter" + +draft: "Utkast" diff --git a/resources/language/_language-tr.yml b/resources/language/_language-tr.yml new file mode 100644 index 000000000..4fe401286 --- /dev/null +++ b/resources/language/_language-tr.yml @@ -0,0 +1,127 @@ +toc-title-document: "İçindekiler" +toc-title-website: "Bu sayfada" + +related-formats-title: "Diğer Formatlar" +related-notebooks-title: "Notebooklar" +source-notebooks-prefix: "Kaynak" +other-links-title: "Diğer Bağlantılar" +code-links-title: "Kod Bağlantıları" +launch-dev-container-title: "Dev Container'ı Başlat" +launch-binder-title: "Binder Başlat" + +article-notebook-label: "Makale Notebook'u" +notebook-preview-download: "Notebook'u İndir" +notebook-preview-download-src: "Kaynak kodunu indir" +notebook-preview-back: "Makaleye Geri Dön" +manuscript-meca-bundle: "MECA Arşivi" + +section-title-abstract: "Özet" +section-title-appendices: "Ekler" +section-title-footnotes: "Dipnotlar" +section-title-references: "Referanslar" +section-title-reuse: "Yeniden kullan" +section-title-copyright: "Telif hakkı" +section-title-citation: "Alıntı" + +appendix-attribution-bibtex: "BibTeX" +appendix-attribution-cite-as: "Lütfen bu çalışmayı şu şekilde alıntılayın:" +appendix-view-license: "Lisansı Görüntüle" + +title-block-author-single: "Yazar" +title-block-author-plural: "Yazarlar" +title-block-affiliation-single: "Kurumsal Üyelik" +title-block-affiliation-plural: "Kurumsal Üyelikler" +title-block-published: "Yayınlanma Tarihi" +title-block-modified: "Değiştirilme Tarihi" +title-block-keywords: "Anahtar kelimeler" + +callout-tip-title: "İpucu" +callout-note-title: "Not" +callout-warning-title: "Uyarı" +callout-important-title: "Önemli" +callout-caution-title: "Dikkat" + +code-summary: "Kod" + +code-line: "Satır" +code-lines: "Satırlar" + +code-tools-menu-caption: "Kod" +code-tools-show-all-code: "Tüm Kodu Göster" +code-tools-hide-all-code: "Tüm Kodu Gizle" +code-tools-view-source: "Kaynağı Görüntüle" +code-tools-source-code: "Kaynak Kodu" + +copy-button-tooltip: "Panoya Kopyala" +copy-button-tooltip-success: "Kopyalandı" + +repo-action-links-edit: "Bu sayfayı düzenle" +repo-action-links-source: "Kaynağı görüntüle" +repo-action-links-issue: "Sorun bildir" + +back-to-top: "Başa dön" + +search-no-results-text: "Sonuç yok" +search-matching-documents-text: "eşleşen belgeler" +search-copy-link-title: "Aramak için bağlantıyı kopyalayın" +search-hide-matches-text: "Ek eşleşmeleri gizle" +search-more-match-text: "bu belgede bir tane daha eşleşme" +search-more-matches-text: "bu belgede daha fazla eşleşme" +search-clear-button-title: "Temizle" +search-text-placeholder: "" +search-detached-cancel-button-title: "İptal et" +search-submit-button-title: "Gönder" +search-label: "Ara" + +toggle-section: "Bölümü değiştir" +toggle-sidebar: "Kenar çubuğunu değiştir" +toggle-dark-mode: "Karanlık modu değiştir" +toggle-reader-mode: "Okuyucu modunu değiştir" +toggle-navigation: "Gezinmeyi değiştir" + +crossref-fig-title: "Şekil" +crossref-tbl-title: "Tablo" +crossref-lst-title: "Listeleme" +crossref-thm-title: "Teorem" +crossref-lem-title: "Yardımcı Teorem" +crossref-cor-title: "Gerekçe" +crossref-prp-title: "Önerme" +crossref-cnj-title: "Varsayım" +crossref-def-title: "Tanım" +crossref-exm-title: "Örnek" +crossref-exr-title: "Egzersiz" +crossref-ch-prefix: "Bölüm" +crossref-apx-prefix: "Ek" +crossref-sec-prefix: "Bölüm" +crossref-eq-prefix: "Eşitlik" +crossref-lof-title: "Şekil Listesi" +crossref-lot-title: "Tablo Listesi" +crossref-lol-title: "İlan Listesi" + +environment-proof-title: "Kanıt" +environment-remark-title: "Görüş" +environment-solution-title: "Çözüm" + +listing-page-order-by: "Sıralama Öğesi" +listing-page-order-by-default: "Varsayılan" +listing-page-order-by-date-asc: "En eski" +listing-page-order-by-date-desc: "En yeni" +listing-page-order-by-number-desc: "Yüksekten Alçağa" +listing-page-order-by-number-asc: "Alcaktan Yükseğe" +listing-page-field-date: "Tarih" +listing-page-field-title: "Başlık" +listing-page-field-description: "Açıklama" +listing-page-field-author: "Yazar" +listing-page-field-filename: "Dosya adı" +listing-page-field-filemodified: "Değiştirilme Tarihi" +listing-page-field-subtitle: "Alt Başlık" +listing-page-field-readingtime: "Okuma Süresi" +listing-page-field-categories: "Kategoriler" +listing-page-minutes-compact: "{0} dakika" +listing-page-category-all: "Hepsi" +listing-page-no-matches: "Eşleşen öğe yok" +listing-page-field-wordcount: "Kelime Sayısı" +listing-page-words: "{0} kelime" +listing-page-filter: "Filtre" + +draft: "Taslak" diff --git a/resources/language/_language-ua.yml b/resources/language/_language-ua.yml new file mode 100644 index 000000000..4b6ac4c1e --- /dev/null +++ b/resources/language/_language-ua.yml @@ -0,0 +1,127 @@ +toc-title-document: "Зміст" +toc-title-website: "Зміст" + +related-formats-title: "Інші формати" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "Джерело" +other-links-title: "Інші посилання" +code-links-title: "Посилання на код" +launch-dev-container-title: "Запустити Dev Container" +launch-binder-title: "Запустити Binder" + +article-notebook-label: "Блокнот статті" +notebook-preview-download: "Завантажити блокнот" +notebook-preview-download-src: "Завантажити вихідний код" +notebook-preview-back: "Повернутися до статті" +manuscript-meca-bundle: "Архів MECA" + +section-title-abstract: "Анотація" +section-title-appendices: "Додатки" +section-title-footnotes: "Примітки" +section-title-references: "Використана література" +section-title-reuse: "Повторне використання" +section-title-copyright: "Авторські права" +section-title-citation: "Цитата" + +appendix-attribution-cite-as: "Будь-ласка, цитуйте цю роботу як:" +appendix-attribution-bibtex: "BibTeX citation:" +appendix-view-license: "Переглянути Ліцензію" + +title-block-author-single: "Автор" +title-block-author-plural: "Автори" +title-block-affiliation-single: "Приналежність" +title-block-affiliation-plural: "Приналежності" +title-block-published: "Дата публікації" +title-block-modified: "Змінено" +title-block-keywords: "Ключові слова" + +callout-tip-title: "Порада" +callout-note-title: "Примітка" +callout-warning-title: "Попередження" +callout-important-title: "Важливо" +callout-caution-title: "Застереження" + +code-summary: "Код" + +code-tools-menu-caption: "Код" +code-tools-show-all-code: "Розгорнути код" +code-tools-hide-all-code: "Сховати код" +code-tools-view-source: "Показати код" +code-tools-source-code: "Вихідний код" + +code-line: "Лінія" +code-lines: "Лінії" + +copy-button-tooltip: "Скопіювати текст" +copy-button-tooltip-success: "Скопійовано!" + +repo-action-links-edit: "Редагувати сторінку" +repo-action-links-source: "Показати код" +repo-action-links-issue: "Повідомити про проблему" + +back-to-top: "Вгору" + +search-no-results-text: "Пошук не дав результатів" +search-matching-documents-text: "Результати пошуку" +search-copy-link-title: "Скопіювати посилання" +search-hide-matches-text: "Сховати додаткові результати" +search-more-match-text: "додатковий результат у цьому документі" +search-more-matches-text: "додаткових результатів у цьому документі" +search-clear-button-title: "Очистити" +search-text-placeholder: "" +search-detached-cancel-button-title: "Відмінити" +search-submit-button-title: "Надіслати" +search-label: "Пошук" + +toggle-section: "Переключити розділ" +toggle-sidebar: "Переключити бокову панель навігації" +toggle-dark-mode: "Переключити темний режим" +toggle-reader-mode: "Переключити режим читання" +toggle-navigation: "Переключити навігацію" + +crossref-fig-title: "Рисунок" +crossref-tbl-title: "Таблиця" +crossref-lst-title: "Список" +crossref-thm-title: "Теорема" +crossref-lem-title: "Лемма" +crossref-cor-title: "Наслідок" +crossref-prp-title: "Твердження" +crossref-cnj-title: "Гіпотеза" +crossref-def-title: "Визначення" +crossref-exm-title: "Приклад" +crossref-exr-title: "Вправа" +crossref-ch-prefix: "Глава" +crossref-apx-prefix: "Додаток" +crossref-sec-prefix: "Розділ" +crossref-eq-prefix: "Рівняння" +crossref-lof-title: "Список рисунків" +crossref-lot-title: "Список таблиць" +crossref-lol-title: "Список Каталогів" + +environment-proof-title: "Доведення" +environment-remark-title: "Примітка" +environment-solution-title: "Рішення" + +listing-page-order-by: "Сортувати за" +listing-page-order-by-default: "Замовчуванням" +listing-page-order-by-date-asc: "Найстарішим" +listing-page-order-by-date-desc: "Новизною" +listing-page-order-by-number-desc: "Спаданням" +listing-page-order-by-number-asc: "Зростанням" +listing-page-field-date: "Дата" +listing-page-field-title: "Заголовок" +listing-page-field-description: "Опис" +listing-page-field-author: "Автор" +listing-page-field-filename: "Назва файлу" +listing-page-field-filemodified: "Змінено" +listing-page-field-subtitle: "Підзаголовок" +listing-page-field-readingtime: "Час читання" +listing-page-field-wordcount: "Кількість слів" +listing-page-field-categories: "Категорії" +listing-page-minutes-compact: "{0} хвилин" +listing-page-category-all: "Все" +listing-page-no-matches: "Немає відповідних елементів" +listing-page-words: "{0} слів" +listing-page-filter: "Фільтр" + +draft: "Чернетка" diff --git a/resources/language/_language-zh-TW.yml b/resources/language/_language-zh-TW.yml new file mode 100644 index 000000000..4f4251aa9 --- /dev/null +++ b/resources/language/_language-zh-TW.yml @@ -0,0 +1,127 @@ +toc-title-document: "目錄" +toc-title-website: "本頁目錄" + +related-formats-title: "其他格式" +related-notebooks-title: "筆記本" +source-notebooks-prefix: "來源" +other-links-title: "其他連結" +code-links-title: "程式碼連結" +launch-dev-container-title: "啟動開發用容器" +launch-binder-title: "啟動 Binder" + +article-notebook-label: "文章筆記本" +notebook-preview-download: "下載筆記本" +notebook-preview-download-src: "下載原始碼" +notebook-preview-back: "返回文章" +manuscript-meca-bundle: "MECA 打包" + +section-title-abstract: "摘要" +section-title-appendices: "附錄" +section-title-footnotes: "腳註" +section-title-references: "參考文獻" +section-title-reuse: "二次使用" +section-title-copyright: "版權" +section-title-citation: "引用格式" + +appendix-attribution-cite-as: "請使用以下引用格式:" +appendix-attribution-bibtex: "BibTeX 引用:" +appendix-view-license: "查看授權" + +title-block-author-single: "作者" +title-block-author-plural: "作者" +title-block-affiliation-single: "隸屬" +title-block-affiliation-plural: "隸屬" +title-block-published: "發佈於" +title-block-modified: "修改於" +title-block-keywords: "關鍵字" + +callout-tip-title: "提示" +callout-note-title: "註釋" +callout-warning-title: "警告" +callout-important-title: "重要" +callout-caution-title: "注意" + +code-summary: "程式碼" + +code-line: "行" +code-lines: "行" + +code-tools-menu-caption: "程式碼" +code-tools-show-all-code: "顯示所有程式碼區塊" +code-tools-hide-all-code: "隱藏所有程式碼區塊" +code-tools-view-source: "查看本頁原始碼" +code-tools-source-code: "原始碼" + +copy-button-tooltip: "複製到剪貼簿" +copy-button-tooltip-success: "已複製" + +repo-action-links-edit: "編輯本頁面" +repo-action-links-source: "查看本頁原始碼" +repo-action-links-issue: "回報問題" + +back-to-top: "回到頂端" + +search-no-results-text: "沒有結果" +search-matching-documents-text: "符合的文件" +search-copy-link-title: "複製搜尋連結" +search-hide-matches-text: "隱藏其他符合的結果" +search-more-match-text: "更多符合結果" +search-more-matches-text: "更多符合結果" +search-clear-button-title: "清除" +search-text-placeholder: "" +search-detached-cancel-button-title: "取消" +search-submit-button-title: "送出" +search-label: "搜尋" + +toggle-section: "切換區段" +toggle-sidebar: "切換側邊欄導航" +toggle-dark-mode: "切換深色模式" +toggle-reader-mode: "切換閱讀器模式" +toggle-navigation: "切換導航列" + +crossref-fig-title: "圖" +crossref-tbl-title: "表" +crossref-lst-title: "列表" +crossref-thm-title: "定理" +crossref-lem-title: "引理" +crossref-cor-title: "推論" +crossref-prp-title: "命題" +crossref-cnj-title: "猜想" +crossref-def-title: "定義" +crossref-exm-title: "例子" +crossref-exr-title: "練習" +crossref-ch-prefix: "章" +crossref-apx-prefix: "附錄" +crossref-sec-prefix: "節" +crossref-eq-prefix: "方程式" +crossref-lof-title: "圖目錄" +crossref-lot-title: "表目錄" +crossref-lol-title: "列表目錄" + +environment-proof-title: "證明" +environment-remark-title: "小結" +environment-solution-title: "答案" + +listing-page-order-by: "排序方式" +listing-page-order-by-default: "預設" +listing-page-order-by-date-asc: "由舊到新" +listing-page-order-by-date-desc: "由新到舊" +listing-page-order-by-number-desc: "由高到低" +listing-page-order-by-number-asc: "由低到高" +listing-page-field-date: "日期" +listing-page-field-title: "標題" +listing-page-field-description: "描述" +listing-page-field-author: "作者" +listing-page-field-filename: "檔案名稱" +listing-page-field-filemodified: "修改時間" +listing-page-field-subtitle: "副標題" +listing-page-field-readingtime: "閱讀時間" +listing-page-field-categories: "類別" +listing-page-minutes-compact: "{0} 分鐘" +listing-page-category-all: "全部" +listing-page-no-matches: "無符合的項目" +listing-page-field-wordcount: "字數統計" +listing-page-words: "{0} 個單詞" +listing-page-filter: "篩選" + +draft: "草稿" diff --git a/resources/language/_language-zh.yml b/resources/language/_language-zh.yml new file mode 100644 index 000000000..121fbd8f0 --- /dev/null +++ b/resources/language/_language-zh.yml @@ -0,0 +1,127 @@ +toc-title-document: "目录" +toc-title-website: "该页面内容" + +related-formats-title: "其他格式" +related-notebooks-title: "笔记本" +source-notebooks-prefix: "资源" +other-links-title: "其他链接" +code-links-title: "代码链接" +launch-dev-container-title: "启动 Dev Container" +launch-binder-title: "启动 Binder" + +article-notebook-label: "文章笔记本" +notebook-preview-download: "下载笔记本" +notebook-preview-download-src: "下载源代码" +notebook-preview-back: "返回文章" +manuscript-meca-bundle: "MECA 存档" + +section-title-abstract: "摘要" +section-title-appendices: "附录" +section-title-footnotes: "脚注" +section-title-references: "参考文献" +section-title-reuse: "二次使用" +section-title-copyright: "版权" +section-title-citation: "引用格式" + +appendix-attribution-bibtex: "BibTeX" +appendix-attribution-cite-as: "请按如下格式引用:" +appendix-view-license: "查看许可协议" + +title-block-author-single: "作者" +title-block-author-plural: "作者" +title-block-affiliation-single: "单位" +title-block-affiliation-plural: "单位" +title-block-published: "发布于" +title-block-modified: "修改于" +title-block-keywords: "关键词" + +callout-tip-title: "提示" +callout-note-title: "注记" +callout-warning-title: "警告" +callout-important-title: "重要" +callout-caution-title: "注意" + +code-summary: "代码" + +code-line: "行" +code-lines: "行" + +code-tools-menu-caption: "代码" +code-tools-show-all-code: "显示所有代码" +code-tools-hide-all-code: "隐藏所有代码" +code-tools-view-source: "查看源代码" +code-tools-source-code: "源代码" + +copy-button-tooltip: "复制到剪贴板" +copy-button-tooltip-success: "已复制" + +repo-action-links-edit: "编辑该页面" +repo-action-links-source: "查看代码" +repo-action-links-issue: "反馈问题" + +back-to-top: "回到顶部" + +search-no-results-text: "没有结果" +search-matching-documents-text: "匹配的文档" +search-copy-link-title: "复制搜索链接" +search-hide-matches-text: "隐藏其它匹配结果" +search-more-match-text: "更多匹配结果" +search-more-matches-text: "更多匹配结果" +search-clear-button-title: "清除" +search-text-placeholder: "" +search-detached-cancel-button-title: "取消" +search-submit-button-title: "提交" +search-label: "搜索" + +toggle-section: "展开或折叠此栏" +toggle-sidebar: "展开或折叠侧边栏导航" +toggle-dark-mode: "切换深色模式" +toggle-reader-mode: "切换阅读器模式" +toggle-navigation: "展开或折叠导航栏" + +crossref-fig-title: "图" +crossref-tbl-title: "表" +crossref-lst-title: "列表" +crossref-thm-title: "定理" +crossref-lem-title: "引理" +crossref-cor-title: "推论" +crossref-prp-title: "命题" +crossref-cnj-title: "猜想" +crossref-def-title: "定义" +crossref-exm-title: "例" +crossref-exr-title: "习题" +crossref-ch-prefix: "章节" +crossref-apx-prefix: "附录" +crossref-sec-prefix: "小节" +crossref-eq-prefix: "式" +crossref-lof-title: "图索引" +crossref-lot-title: "表索引" +crossref-lol-title: "列表索引" + +environment-proof-title: "证明" +environment-remark-title: "注记" +environment-solution-title: "解" + +listing-page-order-by: "排序方式" +listing-page-order-by-default: "默认" +listing-page-order-by-date-asc: "日期升序" +listing-page-order-by-date-desc: "日期降序" +listing-page-order-by-number-desc: "降序" +listing-page-order-by-number-asc: "升序" +listing-page-field-date: "日期" +listing-page-field-title: "标题" +listing-page-field-description: "描述" +listing-page-field-author: "作者" +listing-page-field-filename: "文件名" +listing-page-field-filemodified: "修改时间" +listing-page-field-subtitle: "副标题" +listing-page-field-readingtime: "阅读时间" +listing-page-field-categories: "分类" +listing-page-minutes-compact: "{0} 分钟" +listing-page-category-all: "全部" +listing-page-no-matches: "无匹配项" +listing-page-field-wordcount: "字数统计" +listing-page-words: "{0} 字" +listing-page-filter: "筛选" + +draft: "草稿" diff --git a/resources/language/_language.yml b/resources/language/_language.yml new file mode 100644 index 000000000..f2a7f2280 --- /dev/null +++ b/resources/language/_language.yml @@ -0,0 +1,130 @@ +toc-title-document: "Table of contents" +toc-title-website: "On this page" + +related-formats-title: "Other Formats" +related-notebooks-title: "Notebooks" +source-notebooks-prefix: "Source" +other-links-title: "Other Links" +code-links-title: "Code Links" +launch-dev-container-title: "Launch Dev Container" +launch-binder-title: "Launch Binder" + +article-notebook-label: "Article Notebook" +notebook-preview-download: "Download Notebook" +notebook-preview-download-src: "Download Source" +notebook-preview-back: "Back to Article" +manuscript-meca-bundle: "MECA Bundle" + +section-title-abstract: "Abstract" +section-title-appendices: "Appendices" +section-title-footnotes: "Footnotes" +section-title-references: "References" +section-title-reuse: "Reuse" +section-title-copyright: "Copyright" +section-title-citation: "Citation" + +appendix-attribution-cite-as: "For attribution, please cite this work as:" +appendix-attribution-bibtex: "BibTeX citation:" +appendix-view-license: "View License" + +title-block-author-single: "Author" +title-block-author-plural: "Authors" +title-block-affiliation-single: "Affiliation" +title-block-affiliation-plural: "Affiliations" +title-block-published: "Published" +title-block-modified: "Modified" +title-block-keywords: "Keywords" + +callout-tip-title: "Tip" +callout-note-title: "Note" +callout-warning-title: "Warning" +callout-important-title: "Important" +callout-caution-title: "Caution" + +code-summary: "Code" + +code-tools-menu-caption: "Code" +code-tools-show-all-code: "Show All Code" +code-tools-hide-all-code: "Hide All Code" +code-tools-view-source: "View Source" +code-tools-source-code: "Source Code" + +tools-share: "Share" +tools-download: "Download" + +code-line: "Line" +code-lines: "Lines" + +copy-button-tooltip: "Copy to Clipboard" +copy-button-tooltip-success: "Copied!" + +repo-action-links-edit: "Edit this page" +repo-action-links-source: "View source" +repo-action-links-issue: "Report an issue" + +back-to-top: "Back to top" + +search-no-results-text: "No results" +search-matching-documents-text: "matching documents" +search-copy-link-title: "Copy link to search" +search-hide-matches-text: "Hide additional matches" +search-more-match-text: "more match in this document" +search-more-matches-text: "more matches in this document" +search-clear-button-title: "Clear" +search-text-placeholder: "" +search-detached-cancel-button-title: "Cancel" +search-submit-button-title: "Submit" +search-label: "Search" + +toggle-section: "Toggle section" +toggle-sidebar: "Toggle sidebar navigation" +toggle-dark-mode: "Toggle dark mode" +toggle-reader-mode: "Toggle reader mode" +toggle-navigation: "Toggle navigation" + +crossref-fig-title: "Figure" +crossref-tbl-title: "Table" +crossref-lst-title: "Listing" +crossref-thm-title: "Theorem" +crossref-lem-title: "Lemma" +crossref-cor-title: "Corollary" +crossref-prp-title: "Proposition" +crossref-cnj-title: "Conjecture" +crossref-def-title: "Definition" +crossref-exm-title: "Example" +crossref-exr-title: "Exercise" +crossref-ch-prefix: "Chapter" +crossref-apx-prefix: "Appendix" +crossref-sec-prefix: "Section" +crossref-eq-prefix: "Equation" +crossref-lof-title: "List of Figures" +crossref-lot-title: "List of Tables" +crossref-lol-title: "List of Listings" + +environment-proof-title: "Proof" +environment-remark-title: "Remark" +environment-solution-title: "Solution" + +listing-page-order-by: "Order By" +listing-page-order-by-default: "Default" +listing-page-order-by-date-asc: "Oldest" +listing-page-order-by-date-desc: "Newest" +listing-page-order-by-number-desc: "High to Low" +listing-page-order-by-number-asc: "Low to High" +listing-page-field-date: "Date" +listing-page-field-title: "Title" +listing-page-field-description: "Description" +listing-page-field-author: "Author" +listing-page-field-filename: "File Name" +listing-page-field-filemodified: "Modified" +listing-page-field-subtitle: "Subtitle" +listing-page-field-readingtime: "Reading Time" +listing-page-field-wordcount: "Word Count" +listing-page-field-categories: "Categories" +listing-page-minutes-compact: "{0} min" +listing-page-category-all: "All" +listing-page-no-matches: "No matching items" +listing-page-words: "{0} words" +listing-page-filter: "Filter" + +draft: "Draft"