#!/usr/bin/env node /** * Merges lib/l10n/app_{en,te}.arb with app_{en,te}_more.arb (in-memory) and * writes lib/l10n/app_localizations.dart, app_localizations_en.dart, app_localizations_te.dart. * * Run from package root: node tool/sync_l10n.mjs */ import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const root = path.join(__dirname, ".."); const l10nDir = path.join(root, "lib", "l10n"); function loadArb(name) { const p = path.join(l10nDir, name); return JSON.parse(fs.readFileSync(p, "utf8")); } function merge(base, extra) { return { ...base, ...extra }; } function messageKeys(arb) { return Object.keys(arb).filter((k) => !k.startsWith("@") && k !== "@@locale"); } function placeholdersFor(arb, key) { const meta = arb[`@${key}`]; if (!meta || !meta.placeholders) return null; return Object.keys(meta.placeholders); } function dartEscapeSingle(s) { return s .replace(/\\/g, "\\\\") .replace(/\r\n/g, "\n") .replace(/\n/g, "\\n") .replace(/'/g, "\\'"); } /** Build Dart string literal expr from ICU-ish template (e.g. "Hi, {name}!"). */ function dartReturnExpr(template, params) { let d = template; for (const p of params) { d = d.split(`{${p}}`).join(`$${p}`); } return `'${dartEscapeSingle(d)}'`; } function writeLocalizations(en, te) { const keys = [...new Set([...messageKeys(en), ...messageKeys(te)])].sort(); const abstractDecls = []; const enImpl = []; const teImpl = []; for (const key of keys) { const ph = placeholdersFor(en, key) ?? placeholdersFor(te, key); if (ph && ph.length) { const args = ph.map((p) => `String ${p}`).join(", "); abstractDecls.push(` String ${key}(${args});`); const tplEn = en[key]; const tplTe = te[key] ?? tplEn; enImpl.push(` @override\n String ${key}(${args}) {\n return ${dartReturnExpr(tplEn, ph)};\n }`); teImpl.push(` @override\n String ${key}(${args}) {\n return ${dartReturnExpr(tplTe, ph)};\n }`); } else { abstractDecls.push(` String get ${key};`); const vEn = en[key] ?? ""; const vTe = te[key] ?? vEn; enImpl.push(` @override\n String get ${key} => '${dartEscapeSingle(vEn)}';`); teImpl.push(` @override\n String get ${key} => '${dartEscapeSingle(vTe)}';`); } } const header = `// GENERATED FILE — do not edit by hand. // Source: lib/l10n/app_en.arb + app_en_more.arb (merged). Regenerate: node tool/sync_l10n.mjs `; const main = `${header}import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'app_localizations_en.dart'; import 'app_localizations_te.dart'; abstract class AppLocalizations { AppLocalizations(String locale) : localeName = locale; final String localeName; static AppLocalizations? of(BuildContext context) { return Localizations.of(context, AppLocalizations); } static const LocalizationsDelegate delegate = _AppLocalizationsDelegate(); static const List> localizationsDelegates = >[ delegate, GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ]; static const List supportedLocales = [ Locale('en'), Locale('te'), ]; ${abstractDecls.join("\n\n")} } class _AppLocalizationsDelegate extends LocalizationsDelegate { const _AppLocalizationsDelegate(); @override Future load(Locale locale) { return SynchronousFuture(lookupAppLocalizations(locale)); } @override bool isSupported(Locale locale) => ['en', 'te'].contains(locale.languageCode); @override bool shouldReload(_AppLocalizationsDelegate old) => false; } AppLocalizations lookupAppLocalizations(Locale locale) { switch (locale.languageCode) { case 'en': return AppLocalizationsEn(); case 'te': return AppLocalizationsTe(); } throw FlutterError( 'AppLocalizations.delegate failed to load unsupported locale "\$locale".', ); } `; const enFile = `${header}import 'app_localizations.dart'; class AppLocalizationsEn extends AppLocalizations { AppLocalizationsEn([String locale = 'en']) : super(locale); ${enImpl.join("\n\n")} } `; const teFile = `${header}import 'app_localizations.dart'; class AppLocalizationsTe extends AppLocalizations { AppLocalizationsTe([String locale = 'te']) : super(locale); ${teImpl.join("\n\n")} } `; fs.writeFileSync(path.join(l10nDir, "app_localizations.dart"), main); fs.writeFileSync(path.join(l10nDir, "app_localizations_en.dart"), enFile); fs.writeFileSync(path.join(l10nDir, "app_localizations_te.dart"), teFile); } const baseEn = loadArb("app_en.arb"); const baseTe = loadArb("app_te.arb"); const moreEn = loadArb("app_en_more.arb"); const moreTe = loadArb("app_te_more.arb"); const en = merge(baseEn, moreEn); const te = merge(baseTe, moreTe); writeLocalizations(en, te); console.log("Wrote app_localizations*.dart from merged ARBs.");