feat: begin adding localised text

This commit is contained in:
Anna 2021-10-10 11:39:45 -04:00
parent 708c6c23b4
commit 146abcfc9a
13 changed files with 16246 additions and 2726 deletions

View File

@ -1,7 +1,12 @@
using System.IO;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Lumina;
using Lumina.Data;
using Lumina.Excel;
using Lumina.Excel.GeneratedSheets;
using Lumina.Text;
namespace SourceGenerator {
internal class Program {
@ -24,17 +29,64 @@ namespace SourceGenerator {
this.Data = data;
}
private static StringBuilder DefaultHeader() {
return new StringBuilder("use std::collections::HashMap;\n");
private static StringBuilder DefaultHeader(bool localisedText = false) {
var sb = new StringBuilder("use std::collections::HashMap;\n");
if (localisedText) {
sb.Append("use super::LocalisedText;\n");
}
return sb;
}
private static readonly Dictionary<Language, string> Languages = new() {
[Language.English] = "en",
[Language.Japanese] = "ja",
[Language.German] = "de",
[Language.French] = "fr",
};
private string? GetLocalisedStruct<T>(uint rowId, Func<T, SeString?> nameFunc, uint indent = 0) where T : ExcelRow {
var def = this.Data.GetExcelSheet<T>()!.GetRow(rowId)!;
var defName = nameFunc(def)?.TextValue();
if (string.IsNullOrEmpty(defName)) {
return null;
}
var sb = new StringBuilder();
sb.Append("LocalisedText {\n");
foreach (var (language, key) in Languages) {
var row = this.Data.GetExcelSheet<T>(language)?.GetRow(rowId);
var name = row == null
? defName
: nameFunc(row)?.TextValue().Replace("\"", "\\\"");
name ??= defName;
for (var i = 0; i < indent + 4; i++) {
sb.Append(' ');
}
sb.Append($"{key}: \"{name}\",\n");
}
for (var i = 0; i < indent; i++) {
sb.Append(' ');
}
sb.Append('}');
return sb.ToString();
}
private string GenerateDuties() {
var sb = DefaultHeader();
var sb = DefaultHeader(true);
sb.Append('\n');
sb.Append("#[derive(Debug)]\n");
sb.Append("pub struct DutyInfo {\n");
sb.Append(" pub name: &'static str,\n");
sb.Append(" pub name: LocalisedText,\n");
sb.Append(" pub high_end: bool,\n");
sb.Append(" pub content_kind: ContentKind,\n");
sb.Append("}\n\n");
@ -91,8 +143,8 @@ namespace SourceGenerator {
continue;
}
var name = cfc.Name.TextValue();
if (name.Length <= 0) {
var name = this.GetLocalisedStruct<ContentFinderCondition>(cfc.RowId, row => row.Name, 12);
if (name == null) {
continue;
}
@ -105,7 +157,7 @@ namespace SourceGenerator {
}
sb.Append($" {cfc.RowId} => DutyInfo {{\n");
sb.Append($" name: \"{name}\",\n");
sb.Append($" name: {name},\n");
sb.Append($" high_end: {highEnd},\n");
sb.Append($" content_kind: ContentKind::{contentKind},\n");
sb.Append(" },\n");
@ -155,11 +207,11 @@ namespace SourceGenerator {
}
private string GenerateRoulettes() {
var sb = DefaultHeader();
var sb = DefaultHeader(true);
sb.Append('\n');
sb.Append("#[derive(Debug)]\n");
sb.Append("pub struct RouletteInfo {\n");
sb.Append(" pub name: &'static str,\n");
sb.Append(" pub name: LocalisedText,\n");
sb.Append(" pub pvp: bool,\n");
sb.Append("}\n\n");
@ -171,8 +223,8 @@ namespace SourceGenerator {
continue;
}
var name = cr.Name.TextValue();
if (name.Length <= 0) {
var name = this.GetLocalisedStruct<ContentRoulette>(cr.RowId, row => row.Name, 12);
if (name == null) {
continue;
}
@ -181,7 +233,7 @@ namespace SourceGenerator {
: "false";
sb.Append($" {cr.RowId} => RouletteInfo {{\n");
sb.Append($" name: \"{name}\",\n");
sb.Append($" name: {name},\n");
sb.Append($" pvp: {pvp},\n");
sb.Append(" },\n");
}
@ -218,21 +270,25 @@ namespace SourceGenerator {
}
private string GenerateTerritoryNames() {
var sb = DefaultHeader();
var sb = DefaultHeader(true);
sb.Append("\nlazy_static::lazy_static! {\n");
sb.Append(" pub static ref TERRITORY_NAMES: HashMap<u32, &'static str> = maplit::hashmap! {\n");
sb.Append(" pub static ref TERRITORY_NAMES: HashMap<u32, LocalisedText> = maplit::hashmap! {\n");
foreach (var tt in this.Data.GetExcelSheet<TerritoryType>()!) {
if (tt.RowId == 0 || tt.PlaceName.Row == 0) {
continue;
}
var name = tt.PlaceName.Value!.Name.TextValue().Replace("\"", "\\\"");
if (name.Length <= 0) {
var name = this.GetLocalisedStruct<TerritoryType>(
tt.RowId,
row => row.PlaceName.Value!.Name,
8
);
if (name == null) {
continue;
}
sb.Append($" {tt.RowId} => \"{name}\",\n");
sb.Append($" {tt.RowId} => {name},\n");
}
sb.Append(" };\n");
@ -242,17 +298,19 @@ namespace SourceGenerator {
}
private string GenerateAutoTranslate() {
var sb = DefaultHeader();
var sb = DefaultHeader(true);
sb.Append("\nlazy_static::lazy_static! {\n");
sb.Append(" pub static ref AUTO_TRANSLATE: HashMap<(u32, u32), &'static str> = maplit::hashmap! {\n");
sb.Append(" pub static ref AUTO_TRANSLATE: HashMap<(u32, u32), LocalisedText> = maplit::hashmap! {\n");
foreach (var row in this.Data.GetExcelSheet<Completion>()!) {
var lookup = row.LookupTable.TextValue();
if (lookup is not ("" or "@")) {
// TODO: do lookup
} else {
var text = row.Text.TextValue();
sb.Append($" ({row.Group}, {row.RowId}) => \"{text}\",\n");
var text = this.GetLocalisedStruct<Completion>(row.RowId, row => row.Text, 8);
if (text != null) {
sb.Append($" ({row.Group}, {row.RowId}) => {text},\n");
}
}
}
@ -263,10 +321,15 @@ namespace SourceGenerator {
}
private string GenerateTreasureMaps() {
var sb = DefaultHeader();
var sb = DefaultHeader(true);
sb.Append("\nlazy_static::lazy_static! {\n");
sb.Append(" pub static ref TREASURE_MAPS: HashMap<u32, &'static str> = maplit::hashmap! {\n");
sb.Append(" 0 => \"All Levels\",\n");
sb.Append(" pub static ref TREASURE_MAPS: HashMap<u32, LocalisedText> = maplit::hashmap! {\n");
sb.Append(" 0 => LocalisedText {\n");
sb.Append(" en: \"All Levels\",\n");
sb.Append(" ja: \"All Levels\",\n");
sb.Append(" de: \"All Levels\",\n");
sb.Append(" fr: \"All Levels\",\n");
sb.Append(" },\n");
var i = 1;
foreach (var row in this.Data.GetExcelSheet<TreasureHuntRank>()!) {
@ -275,9 +338,9 @@ namespace SourceGenerator {
continue;
}
var name = row.KeyItemName.Value?.Name.TextValue();
var name = this.GetLocalisedStruct<TreasureHuntRank>(row.RowId, row => row.KeyItemName.Value?.Name, 8);
if (!string.IsNullOrEmpty(name)) {
sb.Append($" {i++} => \"{name}\",\n");
sb.Append($" {i++} => {name},\n");
}
}

View File

@ -3,6 +3,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>

View File

@ -15,3 +15,50 @@ pub use self::{
treasure_maps::TREASURE_MAPS,
worlds::WORLDS,
};
use std::{
cmp::Ordering,
str::FromStr,
};
#[derive(Debug)]
pub struct LocalisedText {
pub en: &'static str,
pub ja: &'static str,
pub de: &'static str,
pub fr: &'static str,
}
impl LocalisedText {
pub fn from_codes(&self, val: &str) -> &'static str {
let mut parts: Vec<(&str, f32)> = val.split(',')
.map(|part| {
let sub_parts: Vec<&str> = part.split(';').collect();
if sub_parts.len() == 1 {
(sub_parts[0], 1.0)
} else if let Ok(val) = f32::from_str(sub_parts[0]) {
(sub_parts[0], val)
} else {
(sub_parts[0], 0.0)
}
})
.collect();
parts.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Less));
if parts.len() == 0 {
return self.en;
}
for (lang, _) in parts {
let first = lang.split('-').next().unwrap();
match first {
"en" => return self.en,
"ja" => return self.ja,
"de" => return self.de,
"fr" => return self.fr,
_ => {},
}
}
self.en
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,151 +1,327 @@
use std::collections::HashMap;
use super::LocalisedText;
#[derive(Debug)]
pub struct RouletteInfo {
pub name: &'static str,
pub name: LocalisedText,
pub pvp: bool,
}
lazy_static::lazy_static! {
pub static ref ROULETTES: HashMap<u32, RouletteInfo> = maplit::hashmap! {
1 => RouletteInfo {
name: "Duty Roulette: Leveling",
name: LocalisedText {
en: "Duty Roulette: Leveling",
ja: "コンテンツルーレット:レべリング",
de: "Zufallsinhalt: Stufensteigerung",
fr: "Mission aléatoire : gain de niveaux",
},
pvp: false,
},
2 => RouletteInfo {
name: "Duty Roulette: Level 50/60/70 Dungeons",
name: LocalisedText {
en: "Duty Roulette: Level 50/60/70 Dungeons",
ja: "コンテンツルーレットレベル50・60・70ダンジョン",
de: "Zufallsinhalt: Stufe 50/60/70",
fr: "Mission aléatoire : donjons nv 50/60/70",
},
pvp: false,
},
3 => RouletteInfo {
name: "Duty Roulette: Main Scenario",
name: LocalisedText {
en: "Duty Roulette: Main Scenario",
ja: "コンテンツルーレット:メインクエスト",
de: "Zufallsinhalt: Hauptszenario",
fr: "Mission aléatoire : épopée",
},
pvp: false,
},
4 => RouletteInfo {
name: "Duty Roulette: Guildhests",
name: LocalisedText {
en: "Duty Roulette: Guildhests",
ja: "コンテンツルーレット:ギルドオーダー",
de: "Zufallsinhalt: Gildengeheiß",
fr: "Mission aléatoire : opérations de guilde",
},
pvp: false,
},
5 => RouletteInfo {
name: "Duty Roulette: Expert",
name: LocalisedText {
en: "Duty Roulette: Expert",
ja: "コンテンツルーレット:エキスパート",
de: "Zufallsinhalt: Experte",
fr: "Mission aléatoire : expert",
},
pvp: false,
},
6 => RouletteInfo {
name: "Duty Roulette: Trials",
name: LocalisedText {
en: "Duty Roulette: Trials",
ja: "コンテンツルーレット:討伐・討滅戦",
de: "Zufallsinhalt: Prüfung",
fr: "Mission aléatoire : défis",
},
pvp: false,
},
7 => RouletteInfo {
name: "Daily Challenge: Frontline",
name: LocalisedText {
en: "Daily Challenge: Frontline",
ja: "デイリーチャレンジ:フロントライン",
de: "Tagesherausforderung: PvP-Front",
fr: "Challenge quotidien : Front",
},
pvp: false,
},
8 => RouletteInfo {
name: "Duty Roulette: Level 80 Dungeons",
name: LocalisedText {
en: "Duty Roulette: Level 80 Dungeons",
ja: "コンテンツルーレットレベル80ダンジョン",
de: "Zufallsinhalt: Stufe 80",
fr: "Mission aléatoire : donjons nv 80",
},
pvp: false,
},
9 => RouletteInfo {
name: "Duty Roulette: Mentor",
name: LocalisedText {
en: "Duty Roulette: Mentor",
ja: "コンテンツルーレット:メンター",
de: "Zufallsinhalt: Mentor",
fr: "Mission aléatoire : mentor",
},
pvp: false,
},
11 => RouletteInfo {
name: "The Feast (Training Match)",
name: LocalisedText {
en: "The Feast (Training Match)",
ja: "ザ・フィースト (カジュアルマッチ)",
de: "The Feast (Übungskampf)",
fr: "The Feast (entraînement)",
},
pvp: true,
},
13 => RouletteInfo {
name: "The Feast (Ranked Match)",
name: LocalisedText {
en: "The Feast (Ranked Match)",
ja: "ザ・フィースト (ランクマッチ)",
de: "The Feast (gewertet)",
fr: "The Feast (classé)",
},
pvp: true,
},
15 => RouletteInfo {
name: "Duty Roulette: Alliance Raids",
name: LocalisedText {
en: "Duty Roulette: Alliance Raids",
ja: "コンテンツルーレット:アライアンスレイド",
de: "Zufallsinhalt: Allianz-Raid",
fr: "Mission aléatoire : raids en alliance",
},
pvp: false,
},
16 => RouletteInfo {
name: "The Feast (Team Ranked Match)",
name: LocalisedText {
en: "The Feast (Team Ranked Match)",
ja: "ザ・フィースト (チーム用ランクマッチ)",
de: "The Feast (Team, gewertet)",
fr: "The Feast (classé/équipe JcJ)",
},
pvp: true,
},
17 => RouletteInfo {
name: "Duty Roulette: Normal Raids",
name: LocalisedText {
en: "Duty Roulette: Normal Raids",
ja: "コンテンツルーレット:ノーマルレイド",
de: "Zufallsinhalt: Normaler Raid",
fr: "Mission aléatoire : raids normaux",
},
pvp: false,
},
18 => RouletteInfo {
name: "Chocobo Race: Sagolii Road",
name: LocalisedText {
en: "Chocobo Race: Sagolii Road",
ja: "チョコボレース:サゴリーロード",
de: "Chocobo-Rennen: Sagolii-Straße",
fr: "Course de chocobos : Route de Sagolii",
},
pvp: false,
},
19 => RouletteInfo {
name: "Chocobo Race: Costa del Sol",
name: LocalisedText {
en: "Chocobo Race: Costa del Sol",
ja: "チョコボレース:コスタ・デル・ソル",
de: "Chocobo-Rennen: Sonnenküste",
fr: "Course de chocobos : Costa del Sol",
},
pvp: false,
},
20 => RouletteInfo {
name: "Chocobo Race: Tranquil Paths",
name: LocalisedText {
en: "Chocobo Race: Tranquil Paths",
ja: "チョコボレース:トランキルパス",
de: "Chocobo-Rennen: Pfad der Seelenruhe",
fr: "Course de chocobos : Sentes tranquilles",
},
pvp: false,
},
21 => RouletteInfo {
name: "Chocobo Race: Random",
name: LocalisedText {
en: "Chocobo Race: Random",
ja: "チョコボレース:コースルーレット",
de: "Chocobo-Rennen: Zufallsstrecke",
fr: "Course de chocobos : aléatoire",
},
pvp: false,
},
22 => RouletteInfo {
name: "Chocobo Race: Sagolii Road (No Rewards)",
name: LocalisedText {
en: "Chocobo Race: Sagolii Road (No Rewards)",
ja: "チョコボレース:サゴリーロード (報酬なし)",
de: "Chocobo-Rennen: Sagolii-Straße (keine Belohnung)",
fr: "Course de chocobos : Route de Sagolii (sans récompense)",
},
pvp: false,
},
23 => RouletteInfo {
name: "Chocobo Race: Costa del Sol (No Rewards)",
name: LocalisedText {
en: "Chocobo Race: Costa del Sol (No Rewards)",
ja: "チョコボレース:コスタ・デル・ソル (報酬なし)",
de: "Chocobo-Rennen: Sonnenküste (keine Belohnung)",
fr: "Course de chocobos : Costa del Sol (sans récompense)",
},
pvp: false,
},
24 => RouletteInfo {
name: "Chocobo Race: Tranquil Paths (No Rewards)",
name: LocalisedText {
en: "Chocobo Race: Tranquil Paths (No Rewards)",
ja: "チョコボレース:トランキルパス (報酬なし)",
de: "Chocobo-Rennen: Pfad der Seelenruhe (keine Belohnung)",
fr: "Course de chocobos : Sentes tranquilles (sans récompense)",
},
pvp: false,
},
25 => RouletteInfo {
name: "Chocobo Race: Random (No Rewards)",
name: LocalisedText {
en: "Chocobo Race: Random (No Rewards)",
ja: "チョコボレース:コースルーレット (報酬なし)",
de: "Chocobo-Rennen: Zufallsstrecke (keine Belohnung)",
fr: "Course de chocobos : aléatoire (sans récompense)",
},
pvp: false,
},
26 => RouletteInfo {
name: "Chocobo Race: Random",
name: LocalisedText {
en: "Chocobo Race: Random",
ja: "チョコボレース:コースルーレット",
de: "Chocobo-Rennen: Zufallsstrecke",
fr: "Course de chocobos : aléatoire",
},
pvp: false,
},
27 => RouletteInfo {
name: "Chocobo Race: Random",
name: LocalisedText {
en: "Chocobo Race: Random",
ja: "チョコボレース:コースルーレット",
de: "Chocobo-Rennen: Zufallsstrecke",
fr: "Course de chocobos : aléatoire",
},
pvp: false,
},
28 => RouletteInfo {
name: "Chocobo Race: Random",
name: LocalisedText {
en: "Chocobo Race: Random",
ja: "チョコボレース:コースルーレット",
de: "Chocobo-Rennen: Zufallsstrecke",
fr: "Course de chocobos : aléatoire",
},
pvp: false,
},
29 => RouletteInfo {
name: "Chocobo Race: Random",
name: LocalisedText {
en: "Chocobo Race: Random",
ja: "チョコボレース:コースルーレット",
de: "Chocobo-Rennen: Zufallsstrecke",
fr: "Course de chocobos : aléatoire",
},
pvp: false,
},
30 => RouletteInfo {
name: "Chocobo Race: Random",
name: LocalisedText {
en: "Chocobo Race: Random",
ja: "チョコボレース:コースルーレット",
de: "Chocobo-Rennen: Zufallsstrecke",
fr: "Course de chocobos : aléatoire",
},
pvp: false,
},
31 => RouletteInfo {
name: "Chocobo Race: Random",
name: LocalisedText {
en: "Chocobo Race: Random",
ja: "チョコボレース:コースルーレット",
de: "Chocobo-Rennen: Zufallsstrecke",
fr: "Course de chocobos : aléatoire",
},
pvp: false,
},
32 => RouletteInfo {
name: "Chocobo Race: Random",
name: LocalisedText {
en: "Chocobo Race: Random",
ja: "チョコボレース:コースルーレット",
de: "Chocobo-Rennen: Zufallsstrecke",
fr: "Course de chocobos : aléatoire",
},
pvp: false,
},
33 => RouletteInfo {
name: "Chocobo Race: Random",
name: LocalisedText {
en: "Chocobo Race: Random",
ja: "チョコボレース:コースルーレット",
de: "Chocobo-Rennen: Zufallsstrecke",
fr: "Course de chocobos : aléatoire",
},
pvp: false,
},
34 => RouletteInfo {
name: "Chocobo Race: Random",
name: LocalisedText {
en: "Chocobo Race: Random",
ja: "チョコボレース:コースルーレット",
de: "Chocobo-Rennen: Zufallsstrecke",
fr: "Course de chocobos : aléatoire",
},
pvp: false,
},
35 => RouletteInfo {
name: "Chocobo Race: Random",
name: LocalisedText {
en: "Chocobo Race: Random",
ja: "チョコボレース:コースルーレット",
de: "Chocobo-Rennen: Zufallsstrecke",
fr: "Course de chocobos : aléatoire",
},
pvp: false,
},
36 => RouletteInfo {
name: "Chocobo Race: Random",
name: LocalisedText {
en: "Chocobo Race: Random",
ja: "チョコボレース:コースルーレット",
de: "Chocobo-Rennen: Zufallsstrecke",
fr: "Course de chocobos : aléatoire",
},
pvp: false,
},
37 => RouletteInfo {
name: "Chocobo Race: Random",
name: LocalisedText {
en: "Chocobo Race: Random",
ja: "チョコボレース:コースルーレット",
de: "Chocobo-Rennen: Zufallsstrecke",
fr: "Course de chocobos : aléatoire",
},
pvp: false,
},
38 => RouletteInfo {
name: "Chocobo Race: Random",
name: LocalisedText {
en: "Chocobo Race: Random",
ja: "チョコボレース:コースルーレット",
de: "Chocobo-Rennen: Zufallsstrecke",
fr: "Course de chocobos : aléatoire",
},
pvp: false,
},
};

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +1,109 @@
use std::collections::HashMap;
use super::LocalisedText;
lazy_static::lazy_static! {
pub static ref TREASURE_MAPS: HashMap<u32, &'static str> = maplit::hashmap! {
0 => "All Levels",
1 => "Leather Treasure Map",
2 => "Leather Treasure Map",
3 => "Goatskin Treasure Map",
4 => "Toadskin Treasure Map",
5 => "Boarskin Treasure Map",
6 => "Peisteskin Treasure Map",
7 => "Leather Buried Treasure Map",
8 => "Archaeoskin Treasure Map",
9 => "Wyvernskin Treasure Map",
10 => "Dragonskin Treasure Map",
11 => "Gaganaskin Treasure Map",
12 => "Gazelleskin Treasure Map",
13 => "Seemingly Special Treasure Map",
14 => "Gliderskin Treasure Map",
15 => "Zonureskin Treasure Map",
16 => "Presumably Special Treasure Map",
pub static ref TREASURE_MAPS: HashMap<u32, LocalisedText> = maplit::hashmap! {
0 => LocalisedText {
en: "All Levels",
ja: "All Levels",
de: "All Levels",
fr: "All Levels",
},
1 => LocalisedText {
en: "Leather Treasure Map",
ja: "Leather Treasure Map",
de: "Leather Treasure Map",
fr: "Leather Treasure Map",
},
2 => LocalisedText {
en: "Leather Treasure Map",
ja: "Leather Treasure Map",
de: "Leather Treasure Map",
fr: "Leather Treasure Map",
},
3 => LocalisedText {
en: "Goatskin Treasure Map",
ja: "Goatskin Treasure Map",
de: "Goatskin Treasure Map",
fr: "Goatskin Treasure Map",
},
4 => LocalisedText {
en: "Toadskin Treasure Map",
ja: "Toadskin Treasure Map",
de: "Toadskin Treasure Map",
fr: "Toadskin Treasure Map",
},
5 => LocalisedText {
en: "Boarskin Treasure Map",
ja: "Boarskin Treasure Map",
de: "Boarskin Treasure Map",
fr: "Boarskin Treasure Map",
},
6 => LocalisedText {
en: "Peisteskin Treasure Map",
ja: "Peisteskin Treasure Map",
de: "Peisteskin Treasure Map",
fr: "Peisteskin Treasure Map",
},
7 => LocalisedText {
en: "Leather Buried Treasure Map",
ja: "Leather Buried Treasure Map",
de: "Leather Buried Treasure Map",
fr: "Leather Buried Treasure Map",
},
8 => LocalisedText {
en: "Archaeoskin Treasure Map",
ja: "Archaeoskin Treasure Map",
de: "Archaeoskin Treasure Map",
fr: "Archaeoskin Treasure Map",
},
9 => LocalisedText {
en: "Wyvernskin Treasure Map",
ja: "Wyvernskin Treasure Map",
de: "Wyvernskin Treasure Map",
fr: "Wyvernskin Treasure Map",
},
10 => LocalisedText {
en: "Dragonskin Treasure Map",
ja: "Dragonskin Treasure Map",
de: "Dragonskin Treasure Map",
fr: "Dragonskin Treasure Map",
},
11 => LocalisedText {
en: "Gaganaskin Treasure Map",
ja: "Gaganaskin Treasure Map",
de: "Gaganaskin Treasure Map",
fr: "Gaganaskin Treasure Map",
},
12 => LocalisedText {
en: "Gazelleskin Treasure Map",
ja: "Gazelleskin Treasure Map",
de: "Gazelleskin Treasure Map",
fr: "Gazelleskin Treasure Map",
},
13 => LocalisedText {
en: "Seemingly Special Treasure Map",
ja: "Seemingly Special Treasure Map",
de: "Seemingly Special Treasure Map",
fr: "Seemingly Special Treasure Map",
},
14 => LocalisedText {
en: "Gliderskin Treasure Map",
ja: "Gliderskin Treasure Map",
de: "Gliderskin Treasure Map",
fr: "Gliderskin Treasure Map",
},
15 => LocalisedText {
en: "Zonureskin Treasure Map",
ja: "Zonureskin Treasure Map",
de: "Zonureskin Treasure Map",
fr: "Zonureskin Treasure Map",
},
16 => LocalisedText {
en: "Presumably Special Treasure Map",
ja: "Presumably Special Treasure Map",
de: "Presumably Special Treasure Map",
fr: "Presumably Special Treasure Map",
},
};
}

View File

@ -45,11 +45,11 @@ impl PartyFinderListing {
self.search_area.contains(SearchAreaFlags::DATA_CENTRE)
}
pub fn duty_name(&self) -> Cow<str> {
pub fn duty_name(&self, codes: &str) -> Cow<str> {
match (&self.duty_type, &self.category) {
(DutyType::Other, DutyCategory::Fates) => {
if let Some(&name) = crate::ffxiv::TERRITORY_NAMES.get(&u32::from(self.duty)) {
return Cow::from(name);
if let Some(name) = crate::ffxiv::TERRITORY_NAMES.get(&u32::from(self.duty)) {
return Cow::from(name.from_codes(codes));
}
return Cow::from("Fates");
@ -60,17 +60,17 @@ impl PartyFinderListing {
(DutyType::Other, DutyCategory::DeepDungeons) if self.duty == 2 => return Cow::from("Heaven-on-High"),
(DutyType::Normal, _) => {
if let Some(info) = crate::ffxiv::DUTIES.get(&u32::from(self.duty)) {
return Cow::from(info.name);
return Cow::from(info.name.from_codes(codes));
}
}
(DutyType::Roulette, _) => {
if let Some(info) = crate::ffxiv::ROULETTES.get(&u32::from(self.duty)) {
return Cow::from(info.name);
return Cow::from(info.name.from_codes(codes));
}
}
(_, DutyCategory::QuestBattles) => return Cow::from("Quest Battles"),
(_, DutyCategory::TreasureHunt) => if let Some(&name) = crate::ffxiv::TREASURE_MAPS.get(&u32::from(self.duty)) {
return Cow::from(name);
(_, DutyCategory::TreasureHunt) => if let Some(name) = crate::ffxiv::TREASURE_MAPS.get(&u32::from(self.duty)) {
return Cow::from(name.from_codes(codes));
}
_ => {}
}

View File

@ -1,18 +1,18 @@
use sestring::{Payload, SeString};
pub trait SeStringExt {
fn full_text(&self) -> String;
fn full_text(&self, codes: &str) -> String;
}
impl SeStringExt for SeString {
fn full_text(&self) -> String {
fn full_text(&self, codes: &str) -> String {
self.0.iter()
.flat_map(|payload| {
match payload {
Payload::Text(t) => Some(&*t.0),
Payload::AutoTranslate(at) => crate::ffxiv::AUTO_TRANSLATE
.get(&(u32::from(at.group), at.key))
.map(std::ops::Deref::deref),
.map(|text| text.from_codes(codes)),
_ => None,
}
})

View File

@ -8,4 +8,5 @@ use crate::listing::PartyFinderCategory;
#[template(path = "listings.html")]
pub struct ListingsTemplate {
pub containers: Vec<QueriedListing>,
pub codes: String,
}

View File

@ -122,8 +122,9 @@ fn index() -> BoxedFilter<(impl Reply, )> {
}
fn listings(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
async fn logic(state: Arc<State>) -> std::result::Result<impl Reply, Infallible> {
async fn logic(state: Arc<State>, codes: Option<String>) -> std::result::Result<impl Reply, Infallible> {
use mongodb::bson::doc;
let codes = codes.unwrap_or_else(|| String::from("en"));
let res = state
.collection()
@ -185,12 +186,14 @@ fn listings(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
Ok(ListingsTemplate {
containers,
codes,
})
}
Err(e) => {
eprintln!("{:#?}", e);
Ok(ListingsTemplate {
containers: Default::default(),
codes,
})
}
})
@ -198,7 +201,12 @@ fn listings(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
let route = warp::path("listings")
.and(warp::path::end())
.and_then(move || logic(Arc::clone(&state)));
.and(
warp::filters::header::optional::<String>("accept-language")
.or(warp::filters::cookie::optional::<String>("lang"))
)
.unify()
.and_then(move |codes: Option<String>| logic(Arc::clone(&state), codes));
warp::get().and(route).boxed()
}

View File

@ -68,9 +68,9 @@ Remote Party Finder
{%- else %}
{%- let duty_class = " local" %}
{%- endif %}
<div class="duty{{ duty_class }}">{{ listing.duty_name() }}</div>
<div class="duty{{ duty_class }}">{{ listing.duty_name(codes.as_str()) }}</div>
<div class="description">
{%- let desc = listing.description.full_text() %}
{%- let desc = listing.description.full_text(codes.as_str()) %}
{%- if desc.trim().is_empty() -%}
<em>None</em>
{%- else -%}
@ -120,7 +120,7 @@ Remote Party Finder
</div>
<div class="right meta">
<div class="item creator">
<span class="text">{{ listing.name.full_text() }} @ {{ listing.home_world_string() }}</span>
<span class="text">{{ listing.name.full_text(codes.as_str()) }} @ {{ listing.home_world_string() }}</span>
<span title="Creator">
<svg class="icon" viewBox="0 0 32 32">
<use href="/assets/icons.svg#user"></use>