@gjsify/node-gi 0.64.12 → 0.64.14

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.
package/gettext.d.ts CHANGED
@@ -1,6 +1,11 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  // @gjsify/node-gi/gettext — types for the GJS `Gettext` module on Node.
3
3
 
4
+ /**
5
+ * Re-derive the process's message languages from the platform. A no-op off Android; on Android
6
+ * call it after the user switches the app locale. Returns the `LANGUAGE` value set, or null.
7
+ */
8
+ export function refreshLocale(): string | null;
4
9
  /** Look up `msgid` in the default domain. */
5
10
  export function gettext(msgid: string): string;
6
11
  /** Look up `msgid` in `domain`. */
@@ -116,14 +116,41 @@ function deriveAppDir() {
116
116
  }
117
117
  }
118
118
 
119
+ // A Vite-built app exposes only the `android.*` packages its own code touched, and nothing
120
+ // touches `android.system` — so `android.system.Os` is undefined there and every setenv
121
+ // silently did nothing (LANGUAGE and XDG_* never reached the native process). Reflection
122
+ // reaches the class whatever the bundle referenced.
123
+ function androidSetenv(name, value) {
124
+ const os = globalThis.android?.system?.Os;
125
+ if (os) {
126
+ os.setenv(name, value, true);
127
+ return;
128
+ }
129
+ const java = globalThis.java;
130
+ if (!java?.lang?.Class) return;
131
+ try {
132
+ const types = java.lang.reflect.Array.newInstance(java.lang.Class.class, 3);
133
+ java.lang.reflect.Array.set(types, 0, java.lang.String.class);
134
+ java.lang.reflect.Array.set(types, 1, java.lang.String.class);
135
+ java.lang.reflect.Array.set(types, 2, java.lang.Boolean.TYPE);
136
+ const args = java.lang.reflect.Array.newInstance(java.lang.Object.class, 3);
137
+ java.lang.reflect.Array.set(args, 0, name);
138
+ java.lang.reflect.Array.set(args, 1, value);
139
+ java.lang.reflect.Array.set(args, 2, java.lang.Boolean.TRUE);
140
+ java.lang.Class.forName('android.system.Os').getMethod('setenv', types).invoke(null, args);
141
+ } catch (e) {
142
+ globalThis.console?.warn?.(`node-gi: setenv(${name}) failed: ${e}`);
143
+ }
144
+ }
145
+
119
146
  function setNativeEnv(name, value) {
120
147
  env[name] = value;
121
- globalThis.android?.system?.Os?.setenv(name, value, true);
148
+ androidSetenv(name, value);
122
149
  }
123
150
 
124
151
  /**
125
152
  * The LANGUAGE value for a list of BCP-47 tags: `de-DE` → `de_DE:de`, `zh-Hans-CN` → `zh_CN:zh`,
126
- * de-duplicated, with `C` last as GLib orders it. Bionic's setlocale accepts only C/C.UTF-8
153
+ * de-duplicated, cut after the first English tag, with `C` last as GLib orders it. Bionic's setlocale accepts only C/C.UTF-8
127
154
  * and Android sets no LANG, so GLib's language list (and the libintl in gi-runtime-android,
128
155
  * which reads LANGUAGE on every lookup) has nothing else to go on. Pure — no device needed.
129
156
  * @param {string[]} tags
@@ -141,6 +168,10 @@ export function languageFromBcp47(tags) {
141
168
  const region = parts.slice(1).find((p) => /^([A-Za-z]{2}|\d{3})$/.test(p));
142
169
  if (region) add(`${lang}_${region.toUpperCase()}`);
143
170
  add(lang);
171
+ // English is the msgid language, so no catalog exists for it and gettext would go on to
172
+ // the NEXT entry: with the app switched to en-US over a German system the list is
173
+ // [en-US, de-DE], and every string came back German. Nothing after English may apply.
174
+ if (lang === 'en') break;
144
175
  }
145
176
  add('C');
146
177
  return out.join(':');
@@ -180,6 +211,37 @@ export function refreshLocale() {
180
211
  return value;
181
212
  }
182
213
 
214
+ let followingSystemLocale = false;
215
+
216
+ /**
217
+ * Re-run `refreshLocale()` whenever the system configuration changes — a language switch is
218
+ * one. The Application-level ComponentCallbacks2 fires whether or not the activity declares
219
+ * `locale` in `configChanges`. Registered once, from the host that owns the LANGUAGE bridge,
220
+ * so no consumer has to know the variable exists.
221
+ * @returns {boolean} whether a callback is registered
222
+ */
223
+ export function followSystemLocale() {
224
+ if (followingSystemLocale) return true;
225
+ try {
226
+ const app = globalThis.com?.tns?.NativeScriptApplication?.getInstance();
227
+ const ComponentCallbacks2 = globalThis.android?.content?.ComponentCallbacks2;
228
+ if (!app || !ComponentCallbacks2) return false;
229
+ app.registerComponentCallbacks(
230
+ new ComponentCallbacks2({
231
+ onConfigurationChanged: () => {
232
+ refreshLocale();
233
+ },
234
+ onLowMemory: () => {},
235
+ onTrimMemory: () => {},
236
+ }),
237
+ );
238
+ followingSystemLocale = true;
239
+ } catch {
240
+ // A callback missing only costs the live switch; the locale at start is still set.
241
+ }
242
+ return followingSystemLocale;
243
+ }
244
+
183
245
  function appDirectory() {
184
246
  const set = globalThis.__NODE_GI_APP_DIR;
185
247
  if (typeof set === 'string' && set !== '') return set;
@@ -225,6 +287,7 @@ function ensureJavaVm(native) {
225
287
 
226
288
  function configureEnvironment() {
227
289
  refreshLocale();
290
+ followSystemLocale();
228
291
  const systemDir = globalThis.__NODE_GI_SYSTEM_DIR;
229
292
  if (typeof systemDir === 'string' && systemDir !== '') {
230
293
  setNativeEnv('XDG_DATA_DIRS', `${systemDir}/share`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/node-gi",
3
- "version": "0.64.12",
3
+ "version": "0.64.14",
4
4
  "description": "GObject-Introspection runtime for Node.js — load gi:// namespaces (GLib/GObject/Gio/…) with GJS-compatible semantics. Vendored + rewritten from node-gtk under MIT.",
5
5
  "type": "module",
6
6
  "license": "MIT",
Binary file
Binary file
Binary file
Binary file