Skip to content

Commit 307a2bc

Browse files
authored
Internationalization part 1 (#467)
Part 1 of (hopefully) 2 for internationalizing Yafc. Primarily, this downloads an appropriate Noto Sans font for languages Roboto doesn't support, and then restarts to switch to that font.
2 parents 48f9c6a + dde7a32 commit 307a2bc

20 files changed

+340
-101
lines changed

Docs/MoreLanguagesSupport.md

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
# YAFC support for more languages
22

3-
YAFC language support is experimental. If your language is missing, that is probably because of one of two reasons:
3+
You can ask Yafc to display non-English names for Factorio objects from the Welcome screen:
4+
- On the Welcome screen, click the language name (probably "English") next to "In-game objects language:"
5+
- Select your language from the drop-down that appears.
6+
- If your language uses non-European glyphs, it may appear at the bottom of the list.
7+
- To use these languages, Yafc may need to do a one-time download of a suitable font.
8+
Click "Confirm" if Yafc asks permission to download a font.
9+
- If you do not wish to have Yafc automatically download a suitable font, click "Select font" in the drop-down, and select a font file that supports your language.
410

5-
- It has less than 90% support in official Factorio translation
6-
- It uses non-European glyphs (such as Chinese or Japanese languages)
7-
8-
You can enable support for your language using this method:
9-
- Navigate to `yafc.config` file located at `%localappdata%\YAFC` (`C:\Users\username\AppData\Local\YAFC`). Open it with the text editor.
10-
- Find `language` section and replace the value with your language code. Here are examples of language codes:
11-
- Chinese (Simplified): `zh-CN`
11+
If your language is supported by Factorio but does not appear in the Welcome screen, you can manually force YAFC to use the strings for your language:
12+
- Navigate to `yafc2.config` file located at `%localappdata%\YAFC` (`C:\Users\username\AppData\Local\YAFC`). Open it with a text editor.
13+
- Find the `language` section and replace the value with your language code. Here are examples of language codes:
14+
- Chinese (Simplified): `zh-CN`
1215
- Chinese (Traditional): `zh-TW`
1316
- Korean: `ko`
1417
- Japanese: `ja`
1518
- Hebrew: `he`
16-
- Else: Look into `Factorio/data/base/locale` folder and find folder with your language.
17-
- If your language have non-European glyphs, you also need to replace fonts: `Yafc/Data/Roboto-Light.ttf` and `Roboto-Regular.ttf` with any fonts that support your language glyphs.
19+
- Else: Look into `Factorio/data/base/locale` folder and find the folder with your language.
20+
- If your language uses non-European glyphs, you also need to replace the fonts `Yafc/Data/Roboto-Light.ttf` and `Roboto-Regular.ttf` with fonts that support your language.
21+
You may also use the "Select font" button in the language dropdown on the Welcome screen to change the font.

Yafc.Model/Analysis/Analysis.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ public static void ProcessAnalyses(IProgress<(string, string)> progress, Project
2121
}
2222
}
2323

24-
public abstract string description { get; }
25-
2624
public static void Do<T>(Project project) where T : Analysis {
2725
foreach (var analysis in analyses) {
2826
if (analysis is T t) {

Yafc.Model/Analysis/AutomationAnalysis.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,4 @@ public override void Compute(Project project, ErrorCollector warnings) {
9090
}
9191
automatable = state;
9292
}
93-
94-
public override string description => "Automation analysis tries to find what objects can be automated. Object cannot be automated if it requires looting an entity or manual crafting.";
9593
}

Yafc.Model/Analysis/CostAnalysis.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -362,10 +362,6 @@ public override void Compute(Project project, ErrorCollector warnings) {
362362
workspaceSolver.Dispose();
363363
}
364364

365-
public override string description => "Cost analysis computes a hypothetical late-game base. This simulation has two very important results: " +
366-
"How much does stuff (items, recipes, etc) cost and how much of stuff do you need. It also collects a bunch of auxiliary results, for example " +
367-
"how efficient are different recipes. These results are used as heuristics and weights for calculations, and are also useful by themselves.";
368-
369365
private static readonly StringBuilder sb = new StringBuilder();
370366
public static string GetDisplayCost(FactorioObject goods) {
371367
float cost = goods.Cost();
@@ -415,6 +411,6 @@ public static string GetDisplayCost(FactorioObject goods) {
415411
return null;
416412
}
417413

418-
return DataUtils.FormatAmount(itemFlow * 1000f, UnitOfMeasure.None, itemAmountPrefix);
414+
return itemAmountPrefix + DataUtils.FormatAmount(itemFlow * 1000f, UnitOfMeasure.None);
419415
}
420416
}

Yafc.Model/Analysis/Milestones.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,4 @@ private static bool[] WalkAccessibilityGraph(Project project, HashSet<FactorioOb
265265
private const string UseDependencyExplorer = "\n\nFor this reason YAFC has a Dependency Explorer that allows you to manually enable some of the core recipes. " +
266266
"YAFC will iteratively try to unlock all the dependencies after each recipe you manually enabled. " +
267267
"For most modpacks it's enough to unlock a few early recipes like any special recipes for plates that everything in the mod is based on.";
268-
269-
public override string description => "Milestone analysis starts from objects that are placed on map by the map generator and tries to find all objects that are accessible from that, " +
270-
"taking notes about which objects are locked behind which milestones.";
271268
}

Yafc.Model/Analysis/TechnologyScienceAnalysis.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,4 @@ public override void Compute(Project project, ErrorCollector warnings) {
108108
allSciencePacks = Database.technologies.CreateMapping(
109109
tech => sciencePackCount.Select((x, id) => x[tech] == 0 ? null : new Ingredient(sciencePacks[id], x[tech])).WhereNotNull().ToArray());
110110
}
111-
112-
public override string description =>
113-
"Technology analysis calculates the total amount of science packs required for each technology";
114111
}

Yafc.Model/Data/DataUtils.cs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -564,25 +564,22 @@ public static string FormatTime(float time) {
564564
return $"{time / 3600f:#} hours";
565565
}
566566

567-
public static string FormatAmount(float amount, UnitOfMeasure unit, string? prefix = null, string? suffix = null, bool precise = false) {
567+
public static string FormatAmount(float amount, UnitOfMeasure unit, bool precise = false) {
568568
var (multiplier, unitSuffix) = Project.current == null ? (1f, null) : Project.current.ResolveUnitOfMeasure(unit);
569569

570-
return FormatAmountRaw(amount, multiplier, unitSuffix, precise ? PreciseFormat : FormatSpec, prefix, suffix);
570+
return FormatAmountRaw(amount, multiplier, unitSuffix, precise ? PreciseFormat : FormatSpec);
571571
}
572572

573-
public static string FormatAmountRaw(float amount, float unitMultiplier, string? unitSuffix, (char suffix, float multiplier, string format)[] formatSpec, string? prefix = null, string? suffix = null) {
573+
public static string FormatAmountRaw(float amount, float unitMultiplier, string? unitSuffix, (char suffix, float multiplier, string format)[] formatSpec) {
574574
if (float.IsNaN(amount) || float.IsInfinity(amount)) {
575575
return "-";
576576
}
577577

578578
if (amount == 0f) {
579-
return prefix + "0" + unitSuffix + suffix;
579+
return "0" + unitSuffix;
580580
}
581581

582582
_ = amountBuilder.Clear();
583-
if (prefix != null) {
584-
_ = amountBuilder.Append(prefix);
585-
}
586583

587584
if (amount < 0) {
588585
_ = amountBuilder.Append('-');
@@ -600,10 +597,6 @@ public static string FormatAmountRaw(float amount, float unitMultiplier, string?
600597

601598
_ = amountBuilder.Append(unitSuffix);
602599

603-
if (suffix != null) {
604-
_ = amountBuilder.Append(suffix);
605-
}
606-
607600
return amountBuilder.ToString();
608601
}
609602

Yafc.Parser/FactorioDataSource.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,16 @@ private static void LoadModLocale(string modName, string locale) {
121121
}
122122
}
123123

124+
public static void LoadYafcLocale(string locale) {
125+
try {
126+
foreach (string localeName in Directory.EnumerateFiles("Data/locale/" + locale + "/")) {
127+
using Stream stream = File.Open(localeName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
128+
FactorioLocalization.Parse(stream);
129+
}
130+
}
131+
catch (DirectoryNotFoundException) { /* No Yafc translation for this locale */ }
132+
}
133+
124134
private static void FindMods(string directory, IProgress<(string, string)> progress, List<ModInfo> mods) {
125135
foreach (string entry in Directory.EnumerateDirectories(directory)) {
126136
string infoFile = Path.Combine(entry, "info.json");

Yafc.UI/Rendering/Font.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.IO;
34
using SDL2;
45

56
namespace Yafc.UI;
@@ -23,11 +24,28 @@ public FontFile.FontSize GetFontSize(float pixelsPreUnit) {
2324
return lastFontSize;
2425
}
2526

27+
/// <summary>
28+
/// Returns <see langword="true"/> if the current font has glyphs for all characters in the supplied string, or <see langword="false"/> if
29+
/// any characters do not have a glyph.
30+
/// </summary>
31+
public bool CanDraw(string value) {
32+
nint handle = lastFontSize!.handle;
33+
foreach (char ch in value) {
34+
if (SDL_ttf.TTF_GlyphIsProvided(handle, ch) == 0) {
35+
return false;
36+
}
37+
}
38+
return true;
39+
}
40+
2641
public IntPtr GetHandle(float pixelsPreUnit) => GetFontSize(pixelsPreUnit).handle;
2742

2843
public float GetLineSize(float pixelsPreUnit) => GetFontSize(pixelsPreUnit).lineSize / pixelsPreUnit;
2944

3045
public void Dispose() => file.Dispose();
46+
47+
public static bool FilesExist(string baseFileName)
48+
=> File.Exists($"Data/{baseFileName}-Regular.ttf") && File.Exists($"Data/{baseFileName}-Light.ttf");
3149
}
3250

3351
public sealed class FontFile(string fileName) : IDisposable {

Yafc/Program.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,16 @@ private static void Main(string[] args) {
2323
Console.Error.WriteException(ex);
2424
}
2525

26+
string baseFileName = "Roboto";
27+
if (WelcomeScreen.languageMapping.TryGetValue(Preferences.Instance.language, out LanguageInfo? language)) {
28+
if (Font.FilesExist(language.BaseFontName)) {
29+
baseFileName = language.BaseFontName;
30+
}
31+
}
32+
2633
hasOverriddenFont = overriddenFontFile != null;
27-
Font.header = new Font(overriddenFontFile ?? new FontFile("Data/Roboto-Light.ttf"), 2f);
28-
var regular = overriddenFontFile ?? new FontFile("Data/Roboto-Regular.ttf");
34+
Font.header = new Font(overriddenFontFile ?? new FontFile($"Data/{baseFileName}-Light.ttf"), 2f);
35+
var regular = overriddenFontFile ?? new FontFile($"Data/{baseFileName}-Regular.ttf");
2936
Font.subheader = new Font(regular, 1.5f);
3037
Font.productionTableHeader = new Font(regular, 1.23f);
3138
Font.text = new Font(regular, 1f);

0 commit comments

Comments
 (0)