using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using Gtk;
public class Language
{
private const string EngCssPath = "lang_eng.css";
private const string JpnCssPath = "lang_jpn.css";
private const string EngCsvPath = "info_eng.csv";
private const string JpnCsvPath = "info_jpn.csv";
private readonly Dictionary<string, string> _engText;
private readonly Dictionary<string, string> _jpnText;
private Dictionary<string, string> _text;
// widgets whose label is a plain CSV lookup
private readonly Dictionary<string, Widget> _widgets = new Dictionary<string, Widget>();
public readonly CssProvider _languageCssProvider = new CssProvider();
public bool IsEnglish { get; private set; }
/// <summary>Raised after every language change, so callers can rebuild state-dependent text.</summary>
public event EventHandler Changed;
public Language(bool isEnglish)
{
StyleContext.AddProviderForScreen(Gdk.Screen.Default, _languageCssProvider, 600);
_engText = LoadText(EngCsvPath);
_jpnText = LoadText(JpnCsvPath);
// set before any widget is built, so ctor-time lookups are already correct
IsEnglish = isEnglish;
_text = isEnglish ? _engText : _jpnText;
}
// ---------- registration ----------
/// <summary>Label comes straight from the CSV key. Applied automatically on every change.</summary>
public void Register(string key, Widget widget)
{
if (widget == null) return;
widget.Name = key; // enables #Key selectors in the lang CSS
_widgets[key] = widget;
}
/// <summary>Widget whose text the owner sets itself (state-dependent). Name only, no auto-apply.</summary>
public void RegisterDynamic(string key, Widget widget)
{
if (widget != null) widget.Name = key;
}
// ---------- lookup ----------
public string this[string key] { get { return Get(key); } }
public string Get(string key)
{
string value;
if (_text.TryGetValue(key, out value)) return value;
Console.WriteLine("Warning: missing text key '" + key + "'");
return key;
}
public string Format(string key, params object[] args)
{
string template = Get(key);
try
{
return string.Format(CultureInfo.InvariantCulture, template, args);
}
catch (FormatException)
{
Console.WriteLine("Warning: bad placeholder in text key '" + key + "'");
return template;
}
}
// ---------- apply ----------
public void Apply(bool isEnglish)
{
IsEnglish = isEnglish;
_text = isEnglish ? _engText : _jpnText;
foreach (var kvp in _widgets)
{
string value;
if (_text.TryGetValue(kvp.Key, out value))
SetText(kvp.Value, value);
else
Console.WriteLine("Warning: missing text key '" + kvp.Key + "'");
}
string cssPath = isEnglish ? EngCssPath : JpnCssPath;
if (File.Exists(cssPath))
_languageCssProvider.LoadFromPath(cssPath);
else
Console.WriteLine("Warning: CSS file not found: " + cssPath);
EventHandler handler = Changed;
if (handler != null) handler(this, EventArgs.Empty);
}
private static void SetText(Widget widget, string value)
{
Button button = widget as Button; // also covers ToggleButton
if (button != null) { button.Label = value; return; }
Label label = widget as Label;
if (label != null) { label.Text = value; return; }
Console.WriteLine("Warning: don't know how to set text on " + widget.GetType().Name);
}
// ---------- csv ----------
private Dictionary<string, string> LoadText(string path)
{
var result = new Dictionary<string, string>();
if (!File.Exists(path))
{
Console.WriteLine("Warning: text file not found: " + path);
return result;
}
string[] lines = File.ReadAllLines(path);
for (int i = 1; i < lines.Length; i++) // row 0 is the header
{
string line = lines[i].Trim();
if (string.IsNullOrEmpty(line) || line.StartsWith("#")) continue;
string[] parts = line.Split(new[] { ',' }, 2);
if (parts.Length < 2) continue;
result[parts[0].Trim()] = parts[1]; // value keeps any commas
}
return result;
}
}