Newer
Older
EARS-LINUX / program / Language.cs
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;
    }
}