@dabalabs/lang 0.0.1-beta → 0.0.2-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -51,6 +51,12 @@ interface LanguageConfig {
51
51
  pathPrefix: string | null;
52
52
  /** Language applied on un-prefixed paths when path routing is on. */
53
53
  isDefault: boolean;
54
+ /** False while the language is still being populated. The switcher
55
+ * omits it, so a visitor is never offered a language that would
56
+ * translate the page live in front of them. Absent (older gateways)
57
+ * counts as ready — a widget must not hide working languages because
58
+ * the server predates the field. */
59
+ ready: boolean;
54
60
  }
55
61
  interface ProjectMetadata {
56
62
  projectId: string;
@@ -94,6 +100,16 @@ declare class DabaLang {
94
100
  * with a prefix match, the widget never machine-translates that page.
95
101
  * (A prefix-less developer language instead swaps its uploaded
96
102
  * catalogue in place.) */
103
+ /** Target languages that actually have translations behind them.
104
+ *
105
+ * A configured-but-unpopulated language is worse than a missing one: a
106
+ * visitor picks it and watches the page translate live, paragraph by
107
+ * paragraph, or lands on a half-translated page while a run is still
108
+ * going. Languages with no config row at all are legacy
109
+ * target_languages entries that predate per-language config — they are
110
+ * shown, because hiding a language that has been serving traffic would
111
+ * be a regression. */
112
+ private readyLanguages;
97
113
  private isSiteTranslated;
98
114
  private selectLanguage;
99
115
  /** Overridable seam for tests — jsdom can't perform real navigation. */
@@ -51,6 +51,12 @@ interface LanguageConfig {
51
51
  pathPrefix: string | null;
52
52
  /** Language applied on un-prefixed paths when path routing is on. */
53
53
  isDefault: boolean;
54
+ /** False while the language is still being populated. The switcher
55
+ * omits it, so a visitor is never offered a language that would
56
+ * translate the page live in front of them. Absent (older gateways)
57
+ * counts as ready — a widget must not hide working languages because
58
+ * the server predates the field. */
59
+ ready: boolean;
54
60
  }
55
61
  interface ProjectMetadata {
56
62
  projectId: string;
@@ -94,6 +100,16 @@ declare class DabaLang {
94
100
  * with a prefix match, the widget never machine-translates that page.
95
101
  * (A prefix-less developer language instead swaps its uploaded
96
102
  * catalogue in place.) */
103
+ /** Target languages that actually have translations behind them.
104
+ *
105
+ * A configured-but-unpopulated language is worse than a missing one: a
106
+ * visitor picks it and watches the page translate live, paragraph by
107
+ * paragraph, or lands on a half-translated page while a run is still
108
+ * going. Languages with no config row at all are legacy
109
+ * target_languages entries that predate per-language config — they are
110
+ * shown, because hiding a language that has been serving traffic would
111
+ * be a regression. */
112
+ private readyLanguages;
97
113
  private isSiteTranslated;
98
114
  private selectLanguage;
99
115
  /** Overridable seam for tests — jsdom can't perform real navigation. */
package/dist/dabalang.js CHANGED
@@ -95,7 +95,10 @@ async function fetchProjectMetadata(gatewayUrl, projectId, apiKey) {
95
95
  code: l.code,
96
96
  provider: l.provider,
97
97
  pathPrefix: l.path_prefix,
98
- isDefault: l.is_default
98
+ isDefault: l.is_default,
99
+ // Absent means an older gateway that has no readiness concept —
100
+ // treat as ready rather than hiding every language.
101
+ ready: l.ready ?? true
99
102
  }))
100
103
  };
101
104
  }
@@ -629,10 +632,14 @@ function injectStyles() {
629
632
  display: inline-flex;
630
633
  align-items: center;
631
634
  gap: 6px;
632
- border: 1px solid rgba(0, 0, 0, 0.12);
633
- background: #ffffff;
634
- color: rgba(0, 0, 0, 0.75);
635
- border-radius: 999px;
635
+ border: 1px solid var(--dabalang-border-color, rgba(0, 0, 0, 0.12));
636
+ background: var(--dabalang-bg, #ffffff);
637
+ color: var(--dabalang-color, rgba(0, 0, 0, 0.75));
638
+ /* Themeable so the switcher can match the host's own buttons. A widget
639
+ cannot know whether a site uses pills or 6px corners, and defaulting
640
+ to a pill made this the one control on the page that did not match.
641
+ Set --dabalang-radius on any ancestor to align it. */
642
+ border-radius: var(--dabalang-radius, 999px);
636
643
  padding: 6px 12px;
637
644
  cursor: pointer;
638
645
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
@@ -899,8 +906,10 @@ function injectStyles() {
899
906
  max-height: 320px;
900
907
  overflow-y: auto;
901
908
  background: #ffffff;
902
- border: 1px solid rgba(0, 0, 0, 0.1);
903
- border-radius: 14px;
909
+ border: 1px solid var(--dabalang-border-color, rgba(0, 0, 0, 0.1));
910
+ /* Panel corners follow the trigger's family, one step softer, so a
911
+ square-cornered host does not get a pill-shaped dropdown. */
912
+ border-radius: var(--dabalang-panel-radius, 14px);
904
913
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.14);
905
914
  padding: 6px;
906
915
  box-sizing: border-box;
@@ -1255,7 +1264,7 @@ var DabaLang = class {
1255
1264
  });
1256
1265
  this.switcher = renderLanguageSwitcher(
1257
1266
  this.container,
1258
- this.metadata.targetLanguages,
1267
+ this.readyLanguages(),
1259
1268
  this.metadata.sourceLang,
1260
1269
  (langCode) => {
1261
1270
  void this.selectLanguage(langCode);
@@ -1283,6 +1292,22 @@ var DabaLang = class {
1283
1292
  * with a prefix match, the widget never machine-translates that page.
1284
1293
  * (A prefix-less developer language instead swaps its uploaded
1285
1294
  * catalogue in place.) */
1295
+ /** Target languages that actually have translations behind them.
1296
+ *
1297
+ * A configured-but-unpopulated language is worse than a missing one: a
1298
+ * visitor picks it and watches the page translate live, paragraph by
1299
+ * paragraph, or lands on a half-translated page while a run is still
1300
+ * going. Languages with no config row at all are legacy
1301
+ * target_languages entries that predate per-language config — they are
1302
+ * shown, because hiding a language that has been serving traffic would
1303
+ * be a regression. */
1304
+ readyLanguages() {
1305
+ const configs = this.metadata?.languages ?? [];
1306
+ return (this.metadata?.targetLanguages ?? []).filter((code) => {
1307
+ const config = configs.find((l) => l.code === code);
1308
+ return config ? config.ready : true;
1309
+ });
1310
+ }
1286
1311
  isSiteTranslated(langCode) {
1287
1312
  const config = this.metadata?.languages.find((l) => l.code === langCode);
1288
1313
  return config?.provider === "developer";