feat: begin adding localised text
This commit is contained in:
parent
708c6c23b4
commit
146abcfc9a
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
})
|
||||
|
|
|
@ -8,4 +8,5 @@ use crate::listing::PartyFinderCategory;
|
|||
#[template(path = "listings.html")]
|
||||
pub struct ListingsTemplate {
|
||||
pub containers: Vec<QueriedListing>,
|
||||
pub codes: String,
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue