Skip to content
GitHub

Internationalization

Internationalization manifests hold translation overrides for one language. At render time every manifest is loaded into the browser-side translation store; components then look labels up under the locale set by ReportArtefact.language.

Three rules determine whether your translations are used:

  1. The locale code must match exactly. Components look up store[namespace][locale][key] where locale is the artefact's spec.languagede or en. There is no BCP 47 normalization: a manifest with code: de-DE passes schema validation but is never consulted when the report renders with language: de — only the i18n-code-unused lint points it out. Always use plain de or en.
  2. The default namespace is _system. That is the namespace every component reads, and where the engine's built-in labels live. When spec.namespace is omitted, your content merges into _system on top of the built-ins, so a partial override just works. A named namespace is only consulted by components whose i18nNamespace points at it (missing keys still fall back to _system per key).
  3. Keys are fixed, dotted strings. The built-in vocabulary below is what components actually request — a key like global.ac1 is a literal string, not a path. Write the map flat; a nested global: block is rejected. Every value must be a string, so quote anything YAML would otherwise read as a number or a boolean (report.year: "2024"). Free-form keys are only useful from a Text component's ${t('…')} templates.

This is the smallest well-formed Internationalization: a language code and the flat map of overrides, merged into the default _system namespace.

apiVersion: bino.bi/v1alpha1
kind: Internationalization
metadata:
  name: labels_de
spec:
  code: de
  content:
    global.ac1: Ist
    global.pl1: Plan
    global.pp1: Vorjahr

All attributes are listed in the Attribute Reference below. Instead of the YAML map, spec.content may also be a JSON string holding the same map, and adding spec.namespace turns the manifest into a scoped override.

Fields:

  • spec.code – language code. It must equal the artefact's spec.language character for character, which in practice means de or en; the schema itself accepts any code of the form de, de-DE or zh_Hans, but a code no artefact uses is only reported by the i18n-code-unused lint.
  • spec.namespace – storage namespace, default _system. Only set this for scoped overrides.
  • spec.content – flat map of dotted keys to label strings, or a JSON string (at least 2 characters) holding the same map.

Multiple manifests for the same namespace and code merge in document order (later wins per key). When a DataSet derives or asserts a previous-period slot with a shift other than a year, bino emits a _system bundle for the artefact language that captions that slot PP instead of the built-in PY. It comes before your manifests, so your own global.pp1 still wins.

These are the keys the components read (values shown are the de / en defaults). Scaffold a complete override file with every token via:

bino add i18n german --code de --defaults --output i18n/de.yaml --no-prompt

Scenario labels (global. prefix — read by tables, charts, and titles)

Section titled “Scenario labels (global. prefix — read by tables, charts, and titles)”
Keydeen
global.ac1global.ac4AC, AC2, AC3, AC4AC, AC2, AC3, AC4
global.pp1global.pp4PY, PY2, PY3, PY4PY, PY2, PY3, PY4
global.fc1global.fc4FC, FC2, FC3, FC4FC, FC2, FC3, FC4
global.pl1global.pl4PL, PL2, PL3, PL4PL, PL2, PL3, PL4

Sort indicators and variance symbols (global. prefix)

Section titled “Sort indicators and variance symbols (global. prefix)”
KeyValueDescription
global.ORDER_asc / global.ORDER_desc↑ / ↓Sort direction indicators
global.ibcssymbol_delta_acΔ{%}Absolute variance symbol (e.g. ΔPY)
global.ibcssymbol_delta_genericΔ({%})Absolute variance, generic form
global.ibcssymbol_delta_ac_relativeΔ{%}%Relative variance symbol (e.g. ΔPY%)
global.ibcssymbol_delta_generic_relativeΔ({%})%Relative variance, generic form

The {%} token is replaced at render time with the comparison scenario's abbreviation.

KeydeenWhat it labels
bn-table.there_ofdavonthere ofRow-header prefix for rows drilled out of their parent
bn-table.part_ofin % vonin % ofRow-header prefix for rows shown as a share of their parent
bn-table.SUM_TOTALThe grand-total row, when spec.sumTitle is not set
bn-table.RESTRESTRESTThe row aggregating everything beyond spec.limit
bn-table.inininPrefix before the measure scale and unit, as in in k€
bn-table.category" "" "Header above the category column (a single space by default)
bn-table.operation" "" "Header above the operation (+/−) column
bn-table.no-data==Keine Daten====No Data==Placeholder when the dataset yields no rows
Keydeen
bn-title.SEPERATOR_WS, ,
bn-title.CONNECTOR_WSundand
bn-title.ininin

Note the key really is spelled SEPERATOR_WS.

Time and structure charts (bn-chart-time., bn-chart-structure. prefixes)

Section titled “Time and structure charts (bn-chart-time., bn-chart-structure. prefixes)”
KeydeenWhat it labels
bn-chart-time.no-data==Keine Daten====No Data==Placeholder when the dataset yields no rows
bn-chart-structure.no-data==Keine Daten====No Data==Placeholder when the dataset yields no rows
bn-chart-structure.RESTRESTRESTThe bar aggregating everything beyond spec.limit

Chart labels (bn-chart-scatter., bn-chart-bubble., bn-chart-bullet. prefixes)

Section titled “Chart labels (bn-chart-scatter., bn-chart-bubble., bn-chart-bullet. prefixes)”
KeydeenRead by
<chart>.no-data==Keine Daten====No Data==scatter, bubble, bullet
<chart>.axis.inininscatter, bubble, bullet
<chart>.legend.titlescatter, bubble — empty by default, which hides the heading
bn-chart-bubble.legend.sizeGrößeSizeHeading for the bubble-size scale
bn-chart-bubble.legend.compareSzenarienScenariosHeading for the compareWith series
bn-chart-bullet.targetZielTargetLegend label for the target marker

Replace <chart> with the component's own prefix — the scatter chart reads bn-chart-scatter.no-data, the bullet chart bn-chart-bullet.no-data, and so on.

Diagnostics are author-facing: they surface in bino preview as component warnings and never appear in the rendered PDF. Only the en default is listed below; run bino add i18n german --code de --defaults to get the German text.

Two different placeholder syntaxes appear in this vocabulary. Diagnostics use {{name}}, substituted with a runtime value. The variance symbols above use {%}, substituted with the comparison scenario's abbreviation. They are not interchangeable.

The scatter and bubble charts raise the same ten messages with identical text. Prefix each suffix with the chart you are overriding — for example bn-chart-bubble.xy-point-budget.

Suffixen defaultWhen it fires
xy-prop-json{{prop}}: invalid JSON.An axis or label property did not parse
xy-measure-invalid{{prop}}: '{{measure}}' is neither a scenario column nor a variance token.A measure name is not recognised
xy-family-mixedAll measures must share one scenario family (found: {{families}}).Measures span more than one scenario family
xy-level-orderFacet, series, and point levels must strictly descend in the hierarchy ({{detail}}).Levels do not descend the hierarchy
xy-duplicate-point{{count}} duplicate point identitie(s) dropped (first row wins): {{names}}. Aggregate in the DataSet SQL.Two rows share a point identity
xy-point-clipped{{count}} point(s) outside the explicit min/max excluded.Points fall outside an explicit axis range
xy-variance-nodata{{count}} row(s) without variance data excluded.Rows lack the data a variance measure needs
xy-label-unknownUnknown label name(s): {{names}}.A configured label names no known column
xy-series-overflowMore series than palette colors; colors repeat with a tint step.More series than the palette has colours
xy-point-budget{{count}} points exceed the 5000-point budget; consider 'limit'.The point budget is exceeded
Keyen defaultWhen it fires
bn-chart-scatter.xy-iso-domainIso-lines need a strictly positive domain on both axes; skipped.Iso-lines are requested but an axis domain includes zero or less
Keyen defaultWhen it fires
bn-chart-bubble.xy-compare-variancecompareWith cannot be combined with variance measures on the axes.compareWith is set alongside variance measures
bn-chart-bubble.bubble-size-negative{{count}} bubble(s) with a negative size value excluded.The size measure is negative
bn-chart-bubble.bubble-share-range{{count}} share value(s) outside [0,1] were clamped.A share value falls outside 0–1
bn-chart-bubble.bubble-scale-group-unknownsize.group '{{group}}' names no bn-scaling-group in scope.size.group names no ScalingGroup
bn-chart-bubble.bubble-scale-overflow{{count}} group-scaled bubble(s) exceed the panel; rendered true-size.Group scaling would push bubbles past the panel
Keyen defaultWhen it fires
bn-chart-bullet.bullet-prop-json{{prop}}: invalid JSON.A property did not parse
bn-chart-bullet.bullet-measure-invalid{{prop}}: '{{measure}}' is not a scenario column (ac1…pl4).A measure is not a scenario column
bn-chart-bullet.bullet-measure-sameactual and target must map different scenarios ('{{measure}}').actual and target name the same scenario
bn-chart-bullet.bullet-target-noneNo target scenario found (pl1/pp1/fc1); rendering actual bars only.No target scenario is present
bn-chart-bullet.bullet-target-missing{{count}} row(s) without a target value; variance and marker omitted.A row has no target value
bn-chart-bullet.bullet-target-invalid{{count}} row(s) with target ≤ 0 cannot be normalized; bar omitted.A target is zero or negative
bn-chart-bullet.bullet-mixed-operation{{count}} KPI group(s) mix '+' and '-' rows; sentiment defaults to '+'.A KPI group mixes + and - rows
bn-chart-bullet.bullet-ranges-ignoredranges: ignored in normalized (IBCS) mode; set normalize="none".ranges is set while normalization is on
bn-chart-bullet.bullet-ranges-invalidranges: expected up to 2 ascending positive fractions of the target ({{detail}}).ranges is not up to two ascending positive fractions

Omit spec.namespace and override only the keys you need — everything else keeps its built-in label:

---
apiVersion: bino.bi/v1alpha1
kind: Internationalization
metadata:
  name: labels_de
spec:
  code: de
  content:
    global.ac1: Ist
    global.pl1: Plan
    global.pp1: Vorjahr

With language: de on the artefact, every table and chart now shows "Ist", "Plan", and "Vorjahr" instead of "AC", "PL", and "PY".

To apply a translation set only to part of a report, store it under a named namespace and point components at it with i18nNamespace. The property is available on ReportArtefact (applies to everything), LayoutPage, LayoutCard, Grid, Tree, and the leaf components that render labels — Table, Text, ChartTime, ChartStructure, ChartScatter, ChartBubble, and ChartBullet. Image has no i18nNamespace. Inheritance is resolved by the engine at render time: a component without its own value uses the nearest ancestor that has one — card, then page, then tree/grid containers, then the artefact. To opt a component out of an inherited namespace, pin it explicitly with i18nNamespace: _system.

---
apiVersion: bino.bi/v1alpha1
kind: Internationalization
metadata:
  name: audited_labels_de
spec:
  code: de
  namespace: audited
  content:
    global.ac1: Ist (geprüft)
---
apiVersion: bino.bi/v1alpha1
kind: LayoutPage
metadata:
  name: audited_page
spec:
  i18nNamespace: audited      # this page's title and all children use it
  children:
    - kind: Table
      spec:
        dataset: revenue
        scenarios: [ac1, pp1]

Keys missing from the named namespace fall back to _system per key, so a scoped namespace only needs the keys it changes.

titleNamespace on LayoutPage/LayoutCard is deprecated: it only ever applied to the page or card title. i18nNamespace takes precedence and also inherits to children.

Text components evaluate ${t('…')} in their value template against the same store, so you can define your own keys:

---
apiVersion: bino.bi/v1alpha1
kind: Internationalization
metadata:
  name: report_texts_de
spec:
  code: de
  content:
    report.title: Umsatzübersicht
---
apiVersion: bino.bi/v1alpha1
kind: Text
metadata:
  name: heading
spec:
  value: "${t('report.title')}"

An unknown key renders as the key itself (it never breaks the component).

  • i18n-code-unused — warns when spec.code matches no artefact language (catches de-DE).
  • i18n-namespace-unreferenced — warns when a named namespace is never referenced by any i18nNamespace.
  • i18n-title-namespace-deprecated — warns on titleNamespace usage.
AttributeTypeRequiredDefaultDescription
apiVersionstringyesMust be bino.bi/v1alpha1.
kindstringyesMust be Internationalization.
metadata.namestringyesUnique identifier for this translation set.
metadata.labelsobjectnoKey-value pairs for categorization and constraint matching.
metadata.annotationsobjectnoArbitrary key-value metadata, not used by the system.
metadata.descriptionstringnoFree-form description.
metadata.constraintsarraynoConditional inclusion rules. See Constraints.
AttributeTypeRequiredDefaultDescriptionSample
spec.codestringyesLanguage code, pattern ^[a-zA-Z]{2,3}([_-][a-zA-Z0-9]{2,8})*$. Only a code that exactly equals an artefact spec.language (de or en) takes effect; de-DE validates but never matches and is reported by i18n-code-unused.code: de
spec.namespacestringno_systemStorage namespace, at least 1 character. The default merges into the bundle every component reads, on top of the built-in labels; a named namespace is only consulted via i18nNamespace.namespace: audited
spec.contentobject, or string of at least 2 charactersyesFlat map of dotted keys to label strings, or a JSON string holding the same map. Nested blocks and non-string values are rejected.global.ac1: Ist, global.pp1: VJ, bn-table.there_of: davon