Add program translation

jp/en/zh -- only english has been translated (duh)
keep in mind this translates the text in the program, not the internal flag names.

not sure if other languages need to be supported; from PKHeX's experience, only spanish is updated (besides jp/zh), as most users speak english or are fine using the program in english.

pls localize villager names and item names for non-english :P -- preferrably automated from raw game dumps
This commit is contained in:
Kurt 2020-04-21 14:26:18 -07:00
parent b4f1bda2c7
commit c9a86cbff9
40 changed files with 27379 additions and 21 deletions

View File

@ -8,14 +8,28 @@
<ItemGroup>
<None Remove="Resources\byte\item_kind.bin" />
<None Remove="Resources\text\en\MessageStrings_en.txt" />
<None Remove="Resources\text\en\text_item_en.txt" />
<None Remove="Resources\text\en\text_villager_en.txt" />
<None Remove="Resources\text\jp\MessageStrings_jp.txt" />
<None Remove="Resources\text\jp\text_item_jp.txt" />
<None Remove="Resources\text\jp\text_villager_jp.txt" />
<None Remove="Resources\text\zh\MessageStrings_zh.txt" />
<None Remove="Resources\text\zh\text_item_zh.txt" />
<None Remove="Resources\text\zh\text_villager_zh.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\byte\item_kind.bin" />
<EmbeddedResource Include="Resources\text\en\MessageStrings_en.txt" />
<EmbeddedResource Include="Resources\text\en\text_item_en.txt" />
<EmbeddedResource Include="Resources\text\en\text_villager_en.txt" />
<EmbeddedResource Include="Resources\text\jp\MessageStrings_jp.txt" />
<EmbeddedResource Include="Resources\text\jp\text_item_jp.txt" />
<EmbeddedResource Include="Resources\text\jp\text_villager_jp.txt" />
<EmbeddedResource Include="Resources\text\zh\MessageStrings_zh.txt" />
<EmbeddedResource Include="Resources\text\zh\text_item_zh.txt" />
<EmbeddedResource Include="Resources\text\zh\text_villager_zh.txt" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,28 @@
MsgBackupCreateLocation=NHSE can perform automatic backups if you create a folder with the name '{0}' in the same folder as the executable.
MsgBackupCreateQuestion=Would you NHSE to automatically keep a backup of your save data?
MsgDataSizeMismatchImport=The size of the imported file (0x{0:X}) does not match the required size (0x{1:X}).
MsgDataSizeMismatchRAM=Read size (0x{0:X}) != Write size (0x{1:X}).
MsgDataDidNotOriginateFromHost_0=Imported data did not originate from Villager0 ({0})'s data.
MsgAskUpdateValues=Update values?
MsgAskContinue=Continue?
MsgAskWriteAnyway=Write anyway?
MsgAskExportResultToClipboard=Export results to clipboard?
MsgCanceling=Canceling:
MsgInvalidHexValue=Bad hex value.
MsgImportDirectoryDoesNotExist=Directory does not exist!
MsgNoPictureLoaded=No picture loaded.
MsgSaveDataImportFail=Unable to open the folder that contains the save file.
MsgSaveDataImportSuggest=Try moving it to another location and opening from there.
MsgSaveDataExportSuccess=Saved all save data!
MsgSaveDataExportFail=Unable to save files to their original location.
MsgSaveDataHashesValid=Hashes are valid.
MsgSaveDataSizeMismatch=Save file sizes appear to be incorrect.
MsgMoveOut=Are you trying to make the Villager move out?
MsgMoveOutSuggest=If so, set the Event Flag (024 - ForceMoveOut) to 1 so that the Villager is removed by the game.
MsgFieldItemRemoveAsk=Are you sure you want to remove {0}?
MsgFieldItemRemoveNone=Nothing removed (none found).
MsgFieldItemRemoveCount=Removed {0} from the map.
MsgSysBotInfo=This SysBot reads and writes RAM directly to your game when called to Read/Write.
MsgSysBotRequired=Using this functionality requires the sys-botbase sysmodule running on the console. Your console must be on the same network as the PC running this program.
MsgTerrainSetElevation0=Set the elevation of all tiles on the map to 0?
MsgTerrainSetAll=Set the tile from the Tile Editor to all tiles on the map?

View File

@ -0,0 +1,28 @@
MsgBackupCreateLocation=NHSE can perform automatic backups if you create a folder with the name '{0}' in the same folder as the executable.
MsgBackupCreateQuestion=Would you NHSE to automatically keep a backup of your save data?
MsgDataSizeMismatchImport=The size of the imported file (0x{0:X}) does not match the required size (0x{1:X}).
MsgDataSizeMismatchRAM=Read size (0x{0:X}) != Write size (0x{1:X}).
MsgDataDidNotOriginateFromHost_0=Imported data did not originate from Villager0 ({0})'s data.
MsgAskUpdateValues=Update values?
MsgAskContinue=Continue?
MsgAskWriteAnyway=Write anyway?
MsgAskExportResultToClipboard=Export results to clipboard?
MsgCanceling=Canceling:
MsgInvalidHexValue=Bad hex value.
MsgImportDirectoryDoesNotExist=Directory does not exist!
MsgNoPictureLoaded=No picture loaded.
MsgSaveDataImportFail=Unable to open the folder that contains the save file.
MsgSaveDataImportSuggest=Try moving it to another location and opening from there.
MsgSaveDataExportSuccess=Saved all save data!
MsgSaveDataExportFail=Unable to save files to their original location.
MsgSaveDataHashesValid=Hashes are valid.
MsgSaveDataSizeMismatch=Save file sizes appear to be incorrect.
MsgMoveOut=Are you trying to make the Villager move out?
MsgMoveOutSuggest=If so, set the Event Flag (024 - ForceMoveOut) to 1 so that the Villager is removed by the game.
MsgFieldItemRemoveAsk=Are you sure you want to remove {0}?
MsgFieldItemRemoveNone=Nothing removed (none found).
MsgFieldItemRemoveCount=Removed {0} from the map.
MsgSysBotInfo=This SysBot reads and writes RAM directly to your game when called to Read/Write.
MsgSysBotRequired=Using this functionality requires the sys-botbase sysmodule running on the console. Your console must be on the same network as the PC running this program.
MsgTerrainSetElevation0=Set the elevation of all tiles on the map to 0?
MsgTerrainSetAll=Set the tile from the Tile Editor to all tiles on the map?

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,397 @@
ant00 Cyrano
ant01 Antonio
ant02 Pango
ant03 Anabelle
ant06 Snooty
ant08 Annalisa
ant09 Olaf
bea00 Teddy
bea01 Pinky
bea02 Curt
bea03 Chow
bea05 Nate
bea06 Groucho
bea07 Tutu
bea08 Ursala
bea09 Grizzly
bea10 Paula
bea11 Ike
bea12 Charlise
bea13 Beardo
bea14 Klaus
bea15 Megan
brd00 Jay
brd01 Robin
brd02 Anchovy
brd03 Twiggy
brd04 Jitters
brd05 Piper
brd06 Admiral
brd08 Midge
brd11 Jakey
brd15 Lucha
brd16 Jacques
brd17 Peck
brd18 Sparro
bul00 Angus
bul01 Rodeo
bul03 Stu
bul05 T-Bone
bul07 Coach
bul08 Vic
cat00 Bob
cat01 Mitzi
cat02 Rosie
cat03 Olivia
cat04 Kiki
cat05 Tangy
cat06 Punchy
cat07 Purrl
cat08 Moe
cat09 Kabuki
cat10 Kid Cat
cat11 Monique
cat12 Tabby
cat13 Stinky
cat14 Kitty
cat15 Tom
cat16 Merry
cat17 Felicity
cat18 Lolly
cat19 Ankha
cat20 Rudy
cat21 Katt
cat23 Raymond
cbr00 Bluebear
cbr01 Maple
cbr02 Poncho
cbr03 Pudge
cbr04 Kody
cbr05 Stitches
cbr06 Vladimir
cbr07 Murphy
cbr09 Olive
cbr10 Cheri
cbr13 June
cbr14 Pekoe
cbr15 Chester
cbr16 Barold
cbr17 Tammy
cbr18 Marty
cbr19 Judy
chn00 Goose
chn01 Benedict
chn02 Egbert
chn05 Ava
chn09 Becky
chn10 Plucky
chn11 Knox
chn12 Broffina
chn13 Ken
cow00 Patty
cow01 Tipper
cow06 Norma
cow07 Naomi
crd00 Alfonso
crd01 Alli
crd02 Boots
crd04 Del
crd06 Sly
crd07 Gayle
crd08 Drago
der00 Fauna
der01 Bam
der02 Zell
der03 Bruce
der04 Deirdre
der05 Lopez
der06 Fuchsia
der07 Beau
der08 Diana
der09 Erik
der10 Chelsea
dog00 Goldie
dog01 Butch
dog02 Lucky
dog03 Biskit
dog04 Bones
dog05 Portia
dog06 Walker
dog07 Daisy
dog08 Cookie
dog09 Maddie
dog10 Bea
dog14 Mac
dog15 Marcel
dog16 Benjamin
dog17 Cherry
dog18 Shep
duk00 Bill
duk01 Joey
duk02 Pate
duk03 Maelle
duk04 Deena
duk05 Pompom
duk06 Mallary
duk07 Freckles
duk08 Derwin
duk09 Drake
duk10 Scoot
duk11 Weber
duk12 Miranda
duk13 Ketchup
duk15 Gloria
duk16 Molly
duk17 Quillson
elp00 Opal
elp01 Dizzy
elp02 Big Top
elp03 Eloise
elp04 Margie
elp05 Paolo
elp06 Axel
elp07 Ellie
elp09 Tucker
elp10 Tia
elp11 Chai
elp12 Cyd
flg00 Lily
flg01 Ribbot
flg02 Frobert
flg03 Camofrog
flg04 Drift
flg05 Wart Jr
flg06 Puddles
flg07 Jeremiah
flg09 Tad
flg10 Cousteau
flg11 Huck
flg12 Prince
flg13 Jambette
flg15 Raddle
flg16 Gigi
flg17 Croque
flg18 Diva
flg19 Henry
goa00 Chevre
goa01 Nan
goa02 Billy
goa04 Gruff
goa06 Velma
goa07 Kidd
goa08 Pashmina
goa09 Sherb
gor00 Cesar
gor01 Peewee
gor02 Boone
gor04 Louie
gor05 Boyd
gor07 Violet
gor08 Al
gor09 Rocket
gor10 Hans
gor11 Rilla
ham00 Hamlet
ham01 Apple
ham02 Graham
ham03 Rodney
ham04 Soleil
ham05 Clay
ham06 Flurry
ham07 Hamphrey
hip00 Rocco
hip02 Bubbles
hip03 Bertha
hip04 Biff
hip05 Bitty
hip08 Harry
hip09 Hippeux
hrs00 Buck
hrs01 Victoria
hrs02 Savannah
hrs03 Elmer
hrs04 Roscoe
hrs05 Winnie
hrs06 Ed
hrs07 Cleo
hrs08 Peaches
hrs09 Annalise
hrs10 Clyde
hrs11 Colton
hrs12 Papi
hrs13 Julian
hrs16 Reneigh
kal00 Yuka
kal01 Alice
kal02 Melba
kal03 Sydney
kal04 Gonzo
kal05 Ozzie
kal08 Canberra
kal09 Lyman
kal10 Eugene
kgr00 Kitt
kgr01 Mathilda
kgr02 Carrie
kgr05 Astrid
kgr06 Sylvia
kgr08 Walt
kgr09 Rooney
kgr10 Marcie
lon00 Bud
lon01 Elvis
lon02 Rex
lon04 Leopold
lon06 Mott
lon07 Rory
lon08 Lionel
mnk01 Nana
mnk02 Simon
mnk03 Tammi
mnk04 Monty
mnk05 Elise
mnk06 Flip
mnk07 Shari
mnk08 Deli
mus00 Dora
mus01 Limberg
mus02 Bella
mus03 Bree
mus04 Samson
mus05 Rod
mus08 Candi
mus09 Rizzo
mus10 Anicotti
mus12 Broccolo
mus14 Moose
mus15 Bettina
mus16 Greta
mus17 Penelope
mus18 Chadder
ocp00 Octavian
ocp01 Marina
ocp02 Zucker
ost00 Queenie
ost01 Gladys
ost02 Sandy
ost03 Sprocket
ost05 Julia
ost06 Cranston
ost07 Phil
ost08 Blanche
ost09 Flora
ost10 Phoebe
pbr00 Apollo
pbr01 Amelia
pbr02 Pierce
pbr03 Buzz
pbr05 Avery
pbr06 Frank
pbr07 Sterling
pbr08 Keaton
pbr09 Celia
pgn00 Aurora
pgn01 Roald
pgn02 Cube
pgn03 Hopper
pgn04 Friga
pgn05 Gwen
pgn06 Puck
pgn09 Wade
pgn10 Boomer
pgn11 Iggly
pgn12 Tex
pgn13 Flo
pgn14 Sprinkle
pig00 Curly
pig01 Truffles
pig02 Rasher
pig03 Hugh
pig04 Lucy
pig05 Crackle
pig08 Cobb
pig09 Boris
pig10 Maggie
pig11 Peggy
pig13 Gala
pig14 Chops
pig15 Kevin
pig16 Pancetti
pig17 Agnes
rbt00 Bunnie
rbt01 Dotty
rbt02 Coco
rbt03 Snake
rbt04 Gaston
rbt05 Gabi
rbt06 Pippy
rbt07 Tiffany
rbt08 Genji
rbt09 Ruby
rbt10 Doc
rbt11 Claude
rbt12 Francine
rbt13 Chrissy
rbt14 Hopkins
rbt15 O'Hare
rbt16 Carmen
rbt17 Bonbon
rbt18 Cole
rbt19 Mira
rbt20 Toby
rhn00 Tank
rhn01 Rhonda
rhn02 Spike
rhn04 Hornsby
rhn07 Merengue
rhn08 Renée
shp00 Vesta
shp01 Baabara
shp02 Eunice
shp03 Stella
shp04 Cashmere
shp07 Willow
shp08 Curlos
shp09 Wendy
shp10 Timbra
shp11 Frita
shp12 Muffy
shp13 Pietro
shp14 Étoile
shp15 Dom
squ00 Peanut
squ01 Blaire
squ02 Filbert
squ03 Pecan
squ04 Nibbles
squ05 Agent S
squ06 Caroline
squ07 Sally
squ08 Static
squ09 Mint
squ10 Ricky
squ11 Cally
squ13 Tasha
squ14 Sylvana
squ15 Poppy
squ16 Sheldon
squ17 Marshal
squ18 Hazel
tig00 Rolf
tig01 Rowan
tig02 Tybalt
tig03 Bangle
tig04 Leonardo
tig05 Claudia
tig06 Bianca
wol00 Chief
wol01 Lobo
wol02 Wolfgang
wol03 Whitney
wol04 Dobie
wol05 Freya
wol06 Fang
wol08 Vivian
wol09 Skye
wol10 Kyle
wol12 Audie

View File

@ -0,0 +1,28 @@
MsgBackupCreateLocation=NHSE can perform automatic backups if you create a folder with the name '{0}' in the same folder as the executable.
MsgBackupCreateQuestion=Would you NHSE to automatically keep a backup of your save data?
MsgDataSizeMismatchImport=The size of the imported file (0x{0:X}) does not match the required size (0x{1:X}).
MsgDataSizeMismatchRAM=Read size (0x{0:X}) != Write size (0x{1:X}).
MsgDataDidNotOriginateFromHost_0=Imported data did not originate from Villager0 ({0})'s data.
MsgAskUpdateValues=Update values?
MsgAskContinue=Continue?
MsgAskWriteAnyway=Write anyway?
MsgAskExportResultToClipboard=Export results to clipboard?
MsgCanceling=Canceling:
MsgInvalidHexValue=Bad hex value.
MsgImportDirectoryDoesNotExist=Directory does not exist!
MsgNoPictureLoaded=No picture loaded.
MsgSaveDataImportFail=Unable to open the folder that contains the save file.
MsgSaveDataImportSuggest=Try moving it to another location and opening from there.
MsgSaveDataExportSuccess=Saved all save data!
MsgSaveDataExportFail=Unable to save files to their original location.
MsgSaveDataHashesValid=Hashes are valid.
MsgSaveDataSizeMismatch=Save file sizes appear to be incorrect.
MsgMoveOut=Are you trying to make the Villager move out?
MsgMoveOutSuggest=If so, set the Event Flag (024 - ForceMoveOut) to 1 so that the Villager is removed by the game.
MsgFieldItemRemoveAsk=Are you sure you want to remove {0}?
MsgFieldItemRemoveNone=Nothing removed (none found).
MsgFieldItemRemoveCount=Removed {0} from the map.
MsgSysBotInfo=This SysBot reads and writes RAM directly to your game when called to Read/Write.
MsgSysBotRequired=Using this functionality requires the sys-botbase sysmodule running on the console. Your console must be on the same network as the PC running this program.
MsgTerrainSetElevation0=Set the elevation of all tiles on the map to 0?
MsgTerrainSetAll=Set the tile from the Tile Editor to all tiles on the map?

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,397 @@
ant00 Cyrano
ant01 Antonio
ant02 Pango
ant03 Anabelle
ant06 Snooty
ant08 Annalisa
ant09 Olaf
bea00 Teddy
bea01 Pinky
bea02 Curt
bea03 Chow
bea05 Nate
bea06 Groucho
bea07 Tutu
bea08 Ursala
bea09 Grizzly
bea10 Paula
bea11 Ike
bea12 Charlise
bea13 Beardo
bea14 Klaus
bea15 Megan
brd00 Jay
brd01 Robin
brd02 Anchovy
brd03 Twiggy
brd04 Jitters
brd05 Piper
brd06 Admiral
brd08 Midge
brd11 Jakey
brd15 Lucha
brd16 Jacques
brd17 Peck
brd18 Sparro
bul00 Angus
bul01 Rodeo
bul03 Stu
bul05 T-Bone
bul07 Coach
bul08 Vic
cat00 Bob
cat01 Mitzi
cat02 Rosie
cat03 Olivia
cat04 Kiki
cat05 Tangy
cat06 Punchy
cat07 Purrl
cat08 Moe
cat09 Kabuki
cat10 Kid Cat
cat11 Monique
cat12 Tabby
cat13 Stinky
cat14 Kitty
cat15 Tom
cat16 Merry
cat17 Felicity
cat18 Lolly
cat19 Ankha
cat20 Rudy
cat21 Katt
cat23 Raymond
cbr00 Bluebear
cbr01 Maple
cbr02 Poncho
cbr03 Pudge
cbr04 Kody
cbr05 Stitches
cbr06 Vladimir
cbr07 Murphy
cbr09 Olive
cbr10 Cheri
cbr13 June
cbr14 Pekoe
cbr15 Chester
cbr16 Barold
cbr17 Tammy
cbr18 Marty
cbr19 Judy
chn00 Goose
chn01 Benedict
chn02 Egbert
chn05 Ava
chn09 Becky
chn10 Plucky
chn11 Knox
chn12 Broffina
chn13 Ken
cow00 Patty
cow01 Tipper
cow06 Norma
cow07 Naomi
crd00 Alfonso
crd01 Alli
crd02 Boots
crd04 Del
crd06 Sly
crd07 Gayle
crd08 Drago
der00 Fauna
der01 Bam
der02 Zell
der03 Bruce
der04 Deirdre
der05 Lopez
der06 Fuchsia
der07 Beau
der08 Diana
der09 Erik
der10 Chelsea
dog00 Goldie
dog01 Butch
dog02 Lucky
dog03 Biskit
dog04 Bones
dog05 Portia
dog06 Walker
dog07 Daisy
dog08 Cookie
dog09 Maddie
dog10 Bea
dog14 Mac
dog15 Marcel
dog16 Benjamin
dog17 Cherry
dog18 Shep
duk00 Bill
duk01 Joey
duk02 Pate
duk03 Maelle
duk04 Deena
duk05 Pompom
duk06 Mallary
duk07 Freckles
duk08 Derwin
duk09 Drake
duk10 Scoot
duk11 Weber
duk12 Miranda
duk13 Ketchup
duk15 Gloria
duk16 Molly
duk17 Quillson
elp00 Opal
elp01 Dizzy
elp02 Big Top
elp03 Eloise
elp04 Margie
elp05 Paolo
elp06 Axel
elp07 Ellie
elp09 Tucker
elp10 Tia
elp11 Chai
elp12 Cyd
flg00 Lily
flg01 Ribbot
flg02 Frobert
flg03 Camofrog
flg04 Drift
flg05 Wart Jr
flg06 Puddles
flg07 Jeremiah
flg09 Tad
flg10 Cousteau
flg11 Huck
flg12 Prince
flg13 Jambette
flg15 Raddle
flg16 Gigi
flg17 Croque
flg18 Diva
flg19 Henry
goa00 Chevre
goa01 Nan
goa02 Billy
goa04 Gruff
goa06 Velma
goa07 Kidd
goa08 Pashmina
goa09 Sherb
gor00 Cesar
gor01 Peewee
gor02 Boone
gor04 Louie
gor05 Boyd
gor07 Violet
gor08 Al
gor09 Rocket
gor10 Hans
gor11 Rilla
ham00 Hamlet
ham01 Apple
ham02 Graham
ham03 Rodney
ham04 Soleil
ham05 Clay
ham06 Flurry
ham07 Hamphrey
hip00 Rocco
hip02 Bubbles
hip03 Bertha
hip04 Biff
hip05 Bitty
hip08 Harry
hip09 Hippeux
hrs00 Buck
hrs01 Victoria
hrs02 Savannah
hrs03 Elmer
hrs04 Roscoe
hrs05 Winnie
hrs06 Ed
hrs07 Cleo
hrs08 Peaches
hrs09 Annalise
hrs10 Clyde
hrs11 Colton
hrs12 Papi
hrs13 Julian
hrs16 Reneigh
kal00 Yuka
kal01 Alice
kal02 Melba
kal03 Sydney
kal04 Gonzo
kal05 Ozzie
kal08 Canberra
kal09 Lyman
kal10 Eugene
kgr00 Kitt
kgr01 Mathilda
kgr02 Carrie
kgr05 Astrid
kgr06 Sylvia
kgr08 Walt
kgr09 Rooney
kgr10 Marcie
lon00 Bud
lon01 Elvis
lon02 Rex
lon04 Leopold
lon06 Mott
lon07 Rory
lon08 Lionel
mnk01 Nana
mnk02 Simon
mnk03 Tammi
mnk04 Monty
mnk05 Elise
mnk06 Flip
mnk07 Shari
mnk08 Deli
mus00 Dora
mus01 Limberg
mus02 Bella
mus03 Bree
mus04 Samson
mus05 Rod
mus08 Candi
mus09 Rizzo
mus10 Anicotti
mus12 Broccolo
mus14 Moose
mus15 Bettina
mus16 Greta
mus17 Penelope
mus18 Chadder
ocp00 Octavian
ocp01 Marina
ocp02 Zucker
ost00 Queenie
ost01 Gladys
ost02 Sandy
ost03 Sprocket
ost05 Julia
ost06 Cranston
ost07 Phil
ost08 Blanche
ost09 Flora
ost10 Phoebe
pbr00 Apollo
pbr01 Amelia
pbr02 Pierce
pbr03 Buzz
pbr05 Avery
pbr06 Frank
pbr07 Sterling
pbr08 Keaton
pbr09 Celia
pgn00 Aurora
pgn01 Roald
pgn02 Cube
pgn03 Hopper
pgn04 Friga
pgn05 Gwen
pgn06 Puck
pgn09 Wade
pgn10 Boomer
pgn11 Iggly
pgn12 Tex
pgn13 Flo
pgn14 Sprinkle
pig00 Curly
pig01 Truffles
pig02 Rasher
pig03 Hugh
pig04 Lucy
pig05 Crackle
pig08 Cobb
pig09 Boris
pig10 Maggie
pig11 Peggy
pig13 Gala
pig14 Chops
pig15 Kevin
pig16 Pancetti
pig17 Agnes
rbt00 Bunnie
rbt01 Dotty
rbt02 Coco
rbt03 Snake
rbt04 Gaston
rbt05 Gabi
rbt06 Pippy
rbt07 Tiffany
rbt08 Genji
rbt09 Ruby
rbt10 Doc
rbt11 Claude
rbt12 Francine
rbt13 Chrissy
rbt14 Hopkins
rbt15 O'Hare
rbt16 Carmen
rbt17 Bonbon
rbt18 Cole
rbt19 Mira
rbt20 Toby
rhn00 Tank
rhn01 Rhonda
rhn02 Spike
rhn04 Hornsby
rhn07 Merengue
rhn08 Renée
shp00 Vesta
shp01 Baabara
shp02 Eunice
shp03 Stella
shp04 Cashmere
shp07 Willow
shp08 Curlos
shp09 Wendy
shp10 Timbra
shp11 Frita
shp12 Muffy
shp13 Pietro
shp14 Étoile
shp15 Dom
squ00 Peanut
squ01 Blaire
squ02 Filbert
squ03 Pecan
squ04 Nibbles
squ05 Agent S
squ06 Caroline
squ07 Sally
squ08 Static
squ09 Mint
squ10 Ricky
squ11 Cally
squ13 Tasha
squ14 Sylvana
squ15 Poppy
squ16 Sheldon
squ17 Marshal
squ18 Hazel
tig00 Rolf
tig01 Rowan
tig02 Tybalt
tig03 Bangle
tig04 Leonardo
tig05 Claudia
tig06 Bianca
wol00 Chief
wol01 Lobo
wol02 Wolfgang
wol03 Whitney
wol04 Dobie
wol05 Freya
wol06 Fang
wol08 Vivian
wol09 Skye
wol10 Kyle
wol12 Audie

View File

@ -7,8 +7,8 @@ public static class GameInfo
{
private static readonly GameStrings?[] Languages = new GameStrings[GameLanguage.LanguageCount];
public static string CurrentLanguage { get; set; } = GameLanguage.DefaultLanguage;
public static GameStrings Strings { get; set; } = GetStrings(CurrentLanguage);
public static string CurrentLanguage { get; private set; } = GameLanguage.DefaultLanguage;
public static GameStrings Strings { get; private set; } = GetStrings(CurrentLanguage);
/// <summary>
/// Gets the Game Strings for a specific language.
@ -24,5 +24,12 @@ public static GameStrings GetStrings(int index)
{
return Languages[index] ??= new GameStrings(GameLanguage.Language2Char(index));
}
public static void SetLanguage2Char(int index)
{
var lang = GameLanguage.Language2Char(index);
CurrentLanguage = lang;
Strings = GetStrings(lang);
}
}
}
}

View File

@ -22,7 +22,7 @@ public static int GetLanguageIndex(string lang)
/// <summary>
/// Language codes supported for loading string resources
/// </summary>
private static readonly string[] LanguageCodes = { "en" };
private static readonly string[] LanguageCodes = { "en", "jp", "zh" };
public static string[] GetStrings(string ident, string lang, string type = "text")
{

View File

@ -0,0 +1,142 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
namespace NHSE.Core
{
public static class ReflectUtil
{
public static bool IsValueEqual(this PropertyInfo pi, object obj, object value)
{
var v = pi.GetValue(obj, null);
var c = ConvertValue(value, pi.PropertyType);
return v.Equals(c);
}
public static void SetValue(PropertyInfo pi, object obj, object value)
{
var c = ConvertValue(value, pi.PropertyType);
pi.SetValue(obj, c, null);
}
public static object? GetValue(object obj, string name) => GetPropertyInfo(obj.GetType().GetTypeInfo(), name)?.GetValue(obj);
public static void SetValue(object obj, string name, object value) => GetPropertyInfo(obj.GetType().GetTypeInfo(), name)?.SetValue(obj, value, null);
public static object GetValue(Type t, string propertyName) => t.GetTypeInfo().GetDeclaredProperty(propertyName).GetValue(null);
public static void SetValue(Type t, string propertyName, object value) => t.GetTypeInfo().GetDeclaredProperty(propertyName).SetValue(null, value);
public static IEnumerable<string> GetPropertiesStartWithPrefix(Type type, string prefix)
{
return type.GetTypeInfo().GetAllTypeInfo().SelectMany(GetAllProperties)
.Where(p => p.Name.StartsWith(prefix, StringComparison.Ordinal))
.Select(p => p.Name)
.Distinct()
;
}
public static IEnumerable<string> GetPropertiesCanWritePublic(Type type)
{
return GetAllPropertyInfoCanWritePublic(type).Select(p => p.Name)
.Distinct()
;
}
public static IEnumerable<PropertyInfo> GetAllPropertyInfoCanWritePublic(Type type)
{
return type.GetTypeInfo().GetAllTypeInfo().SelectMany(GetAllProperties)
.Where(p => p.CanWrite && p.SetMethod.IsPublic);
}
public static IEnumerable<PropertyInfo> GetAllPropertyInfoPublic(Type type)
{
return type.GetTypeInfo().GetAllTypeInfo().SelectMany(GetAllProperties)
.Where(p => (p.CanRead && p.GetMethod.IsPublic) || (p.CanWrite && p.SetMethod.IsPublic));
}
public static IEnumerable<string> GetPropertiesPublic(Type type)
{
return GetAllPropertyInfoPublic(type).Select(p => p.Name)
.Distinct()
;
}
public static IEnumerable<string> GetPropertiesCanWritePublicDeclared(Type type)
{
return type.GetTypeInfo().GetAllProperties()
.Where(p => p.CanWrite && p.SetMethod.IsPublic)
.Select(p => p.Name)
.Distinct()
;
}
private static object? ConvertValue(object value, Type type)
{
if (type == typeof(DateTime?)) // Used for PKM.MetDate and other similar properties
{
return DateTime.TryParseExact(value.ToString(), "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateValue)
? new DateTime?(dateValue)
: null;
}
// Convert.ChangeType is suitable for most things
return Convert.ChangeType(value, type);
}
public static IEnumerable<ConstructorInfo> GetAllConstructors(this TypeInfo typeInfo)
=> GetAll(typeInfo, ti => ti.DeclaredConstructors);
public static IEnumerable<EventInfo> GetAllEvents(this TypeInfo typeInfo)
=> GetAll(typeInfo, ti => ti.DeclaredEvents);
public static IEnumerable<FieldInfo> GetAllFields(this TypeInfo typeInfo)
=> GetAll(typeInfo, ti => ti.DeclaredFields);
public static IEnumerable<MemberInfo> GetAllMembers(this TypeInfo typeInfo)
=> GetAll(typeInfo, ti => ti.DeclaredMembers);
public static IEnumerable<MethodInfo> GetAllMethods(this TypeInfo typeInfo)
=> GetAll(typeInfo, ti => ti.DeclaredMethods);
public static IEnumerable<TypeInfo> GetAllNestedTypes(this TypeInfo typeInfo)
=> GetAll(typeInfo, ti => ti.DeclaredNestedTypes);
public static IEnumerable<PropertyInfo> GetAllProperties(this TypeInfo typeInfo)
=> GetAll(typeInfo, ti => ti.DeclaredProperties);
public static IEnumerable<TypeInfo> GetAllTypeInfo(this TypeInfo? typeInfo)
{
while (typeInfo != null)
{
yield return typeInfo;
typeInfo = typeInfo.BaseType?.GetTypeInfo();
}
}
public static bool HasProperty(object obj, string name, out PropertyInfo? pi) => (pi = GetPropertyInfo(obj.GetType().GetTypeInfo(), name)) != null;
public static PropertyInfo? GetPropertyInfo(this TypeInfo typeInfo, string name)
{
return typeInfo.GetAllTypeInfo().Select(t => t.GetDeclaredProperty(name)).FirstOrDefault(pi => pi != null);
}
private static IEnumerable<T> GetAll<T>(this TypeInfo typeInfo, Func<TypeInfo, IEnumerable<T>> accessor)
{
return GetAllTypeInfo(typeInfo).SelectMany(_ => accessor(typeInfo));
}
public static Dictionary<T, string> GetAllConstantsOfType<T>(this Type type)
{
var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy);
var consts = fields.Where(fi => fi.IsLiteral && !fi.IsInitOnly && fi.FieldType == typeof(T));
return consts.ToDictionary(x => (T)x.GetRawConstantValue(), z => z.Name);
}
public static Dictionary<T, string> GetAllPropertiesOfType<T>(this Type type, object obj)
{
var props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
var ofType = props.Where(fi => typeof(T).IsAssignableFrom(fi.PropertyType));
return ofType.ToDictionary(x => (T)x.GetValue(obj), z => z.Name);
}
}
}

View File

@ -672,12 +672,14 @@ private void InitializeComponent()
//
// Menu_Language
//
this.Menu_Language.Enabled = false;
this.Menu_Language.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.Menu_Language.Items.AddRange(new object[] {
"English"});
"English",
"日本語",
"简体中文"});
this.Menu_Language.Name = "Menu_Language";
this.Menu_Language.Size = new System.Drawing.Size(115, 23);
this.Menu_Language.Text = "Language";
this.Menu_Language.SelectedIndexChanged += new System.EventHandler(this.Menu_Language_SelectedIndexChanged);
//
// Editor
//

View File

@ -18,6 +18,10 @@ public sealed partial class Editor : Form
public Editor(HorizonSave file)
{
InitializeComponent();
Menu_Language.SelectedIndex = 0; // en -- triggers translation
// this.TranslateInterface(GameInfo.CurrentLanguage);
SAV = file;
LoadPlayers();
@ -25,7 +29,6 @@ public Editor(HorizonSave file)
Villagers = LoadVillagers();
Text = SAV.GetSaveTitle("NHSE");
Menu_Language.SelectedIndex = 0; // en
}
private void Menu_Settings_Click(object sender, EventArgs e)
@ -34,6 +37,15 @@ private void Menu_Settings_Click(object sender, EventArgs e)
editor.ShowDialog();
}
private void Menu_Language_SelectedIndexChanged(object sender, EventArgs e)
{
Menu_Options.DropDown.Close();
if ((uint)Menu_Language.SelectedIndex >= GameLanguage.LanguageCount)
return;
GameInfo.SetLanguage2Char(Menu_Language.SelectedIndex);
this.TranslateInterface(GameInfo.CurrentLanguage);
}
private void Menu_Save_Click(object sender, EventArgs e)
{
SaveAll();

View File

@ -157,7 +157,13 @@ private static void BackupSaveFile(HorizonSave file, string path, string bak)
private void Main_KeyDown(object sender, KeyEventArgs e)
{
if (ModifierKeys != Keys.Control)
{
#if DEBUG
if (ModifierKeys == (Keys.Control | Keys.Alt) && e.KeyCode == Keys.D)
DevUtil.UpdateAll();
#endif
return;
}
switch (e.KeyCode)
{

View File

@ -69,5 +69,86 @@ internal class Resources {
return ((System.Drawing.Icon)(obj));
}
}
/// <summary>
/// Looks up a localized string similar to AcreEditor=Acre Editor
///ActivityEditor=Record Editor
///BuildingEditor=Building Editor
///FieldItemEditor=Field Item Editor
///FlagEditor=Flag Editor
///ItemReceivedEditor=Received Item List Editor
///SimpleHexEditor=RAM Edit
///SysBotRAMEdit=SysBotUI
///SysBotUI=SysBotUI
///TerrainEditor=Terrain Editor
///AcreEditor.B_Cancel=Cancel
///AcreEditor.B_Export=Export
///AcreEditor.B_Import=Import
///AcreEditor.B_Save=Save
///AcreEditor.L_AcreList=Name Table:
///AcreEditor.L_Hovered=Hovered
///AcreEditor.L_X0=x
///AcreEditor.L_X1=1
///AcreEditor. [rest of string was truncated]&quot;;.
/// </summary>
internal static string lang_en {
get {
return ResourceManager.GetString("lang_en", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to AcreEditor=Acre Editor
///ActivityEditor=Record Editor
///BuildingEditor=Building Editor
///FieldItemEditor=Field Item Editor
///FlagEditor=Flag Editor
///ItemReceivedEditor=Received Item List Editor
///SimpleHexEditor=RAM Edit
///SysBotRAMEdit=SysBotUI
///SysBotUI=SysBotUI
///TerrainEditor=Terrain Editor
///AcreEditor.B_Cancel=Cancel
///AcreEditor.B_Export=Export
///AcreEditor.B_Import=Import
///AcreEditor.B_Save=Save
///AcreEditor.L_AcreList=Name Table:
///AcreEditor.L_Hovered=Hovered
///AcreEditor.L_X0=x
///AcreEditor.L_X1=1
///AcreEditor. [rest of string was truncated]&quot;;.
/// </summary>
internal static string lang_jp {
get {
return ResourceManager.GetString("lang_jp", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to AcreEditor=Acre Editor
///ActivityEditor=Record Editor
///BuildingEditor=Building Editor
///FieldItemEditor=Field Item Editor
///FlagEditor=Flag Editor
///ItemReceivedEditor=Received Item List Editor
///SimpleHexEditor=RAM Edit
///SysBotRAMEdit=SysBotUI
///SysBotUI=SysBotUI
///TerrainEditor=Terrain Editor
///AcreEditor.B_Cancel=Cancel
///AcreEditor.B_Export=Export
///AcreEditor.B_Import=Import
///AcreEditor.B_Save=Save
///AcreEditor.L_AcreList=Name Table:
///AcreEditor.L_Hovered=Hovered
///AcreEditor.L_X0=x
///AcreEditor.L_X1=1
///AcreEditor. [rest of string was truncated]&quot;;.
/// </summary>
internal static string lang_zh {
get {
return ResourceManager.GetString("lang_zh", resourceCulture);
}
}
}
}

View File

@ -121,4 +121,13 @@
<data name="icon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\icon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="lang_en" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\text\lang_en.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="lang_jp" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\text\lang_jp.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="lang_zh" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\text\lang_zh.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
</root>

View File

@ -0,0 +1,142 @@
AcreEditor=Acre Editor
ActivityEditor=Record Editor
BuildingEditor=Building Editor
FieldItemEditor=Field Item Editor
FlagEditor=Flag Editor
ItemReceivedEditor=Received Item List Editor
SimpleHexEditor=RAM Edit
SysBotRAMEdit=SysBotUI
SysBotUI=SysBotUI
TerrainEditor=Terrain Editor
AcreEditor.B_Cancel=Cancel
AcreEditor.B_Export=Export
AcreEditor.B_Import=Import
AcreEditor.B_Save=Save
AcreEditor.L_AcreList=Name Table:
AcreEditor.L_Hovered=Hovered
ActivityEditor.B_Cancel=Cancel
ActivityEditor.B_Save=Save
ActivityEditor.L_Count=Count:
BuildingEditor.B_Cancel=Cancel
BuildingEditor.B_Dump=Dump
BuildingEditor.B_Import=Import
BuildingEditor.B_Save=Save
BuildingEditor.GB_Building=Editor
BuildingEditor.GB_Info=Info
BuildingEditor.L_Bit=Bit:
BuildingEditor.L_BuildingRotation=Angle:
BuildingEditor.L_BuildingStructureArg=TypeArg:
BuildingEditor.L_BuildingStructureType=Type:
BuildingEditor.L_BuildingType=Building Type:
BuildingEditor.L_BuildingUniqueID=UniqueID:
BuildingEditor.L_BuildingX=X:
BuildingEditor.L_BuildingY=Y:
BuildingEditor.L_PlazaX=Plaza X:
BuildingEditor.L_PlazaY=Plaza Y:
BuildingEditor.L_StructureType=Structure Type:
BuildingEditor.L_StructureValues=Values:
Editor.B_DumpDesign=Dump Design
Editor.B_DumpHouse=Dump House
Editor.B_EditAchievements=Edit Achievements
Editor.B_EditAcres=Edit Acres
Editor.B_EditBuildings=Edit Buildings
Editor.B_EditFieldItems=Edit Field Items
Editor.B_EditLandFlags=Edit Flags
Editor.B_EditPlayerFlags=Edit Flags
Editor.B_EditPlayerItems=Edit Items
Editor.B_EditPlayerReceivedItems=Edit Received Items
Editor.B_EditPlayerRecipes=Edit Recipes
Editor.B_EditPlayerStorage=Edit Storage
Editor.B_EditTerrain=Edit Terrain
Editor.B_EditTurnipExchange=Edit Turnip Exchange
Editor.B_LoadDesign=Load Design
Editor.B_LoadHouse=Load House
Editor.B_RecycleBin=Edit Recycle Bin
Editor.L_BankBells=Bank Bells:
Editor.L_NookMiles=Nook Miles:
Editor.L_PatternIndex=Design Index:
Editor.L_PatternName=*PatternName
Editor.L_PlayerHouse=Player House:
Editor.L_PlayerName=Player Name:
Editor.L_TownName=Town Name:
Editor.L_Wallet=Wallet:
Editor.Menu_DumpDecrypted=Dump Decrypted
Editor.Menu_File=File
Editor.Menu_LoadDecrypted=Load Decrypted
Editor.Menu_Options=Options
Editor.Menu_RAMEdit=RAM Edit
Editor.Menu_Save=Save
Editor.Menu_SavePNG=Save .png
Editor.Menu_Settings=Settings
Editor.Menu_Tools=Tools
Editor.Menu_VerifyHashes=Verify Hashes
Editor.Tab_Designs=Designs
Editor.Tab_Map=Map
Editor.Tab_Players=Players
Editor.Tab_Villagers=Villagers
FieldItemEditor.B_Cancel=Cancel
FieldItemEditor.B_Down=↓
FieldItemEditor.B_DumpAcre=Dump Acre
FieldItemEditor.B_DumpAllAcres=Dump All Acres
FieldItemEditor.B_FillHoles=Holes
FieldItemEditor.B_ImportAcre=Import Acre
FieldItemEditor.B_ImportAllAcres=Import All Acres
FieldItemEditor.B_Left=←
FieldItemEditor.B_RemoveAll=All
FieldItemEditor.B_RemoveAllWeeds=Weeds
FieldItemEditor.B_RemoveFences=Fences
FieldItemEditor.B_RemoveObjects=Non-Items
FieldItemEditor.B_RemovePlacedItems=Placed Items
FieldItemEditor.B_RemovePlants=Plants
FieldItemEditor.B_Right=→
FieldItemEditor.B_Save=Save
FieldItemEditor.B_Up=↑
FieldItemEditor.CHK_SnapToAcre=Snap to nearest Acre on Click
FieldItemEditor.GB_Remove=Remove from View (Hold Shift=Map)
FieldItemEditor.L_Acre=Acre:
FieldItemEditor.L_Layer=Layer:
FieldItemEditor.Menu_Reset=Reset
FieldItemEditor.Menu_SavePNG=Save .png
FieldItemEditor.Menu_Set=Set
FieldItemEditor.Menu_View=View
FlagEditor.B_Cancel=Cancel
FlagEditor.B_Save=Save
FlagEditor.L_Count=Value:
ItemReceivedEditor.B_AllBugs=Give All Bugs
ItemReceivedEditor.B_AllFish=Give All Fish
ItemReceivedEditor.B_Cancel=Cancel
ItemReceivedEditor.B_GiveAll=Give All
ItemReceivedEditor.B_Save=Save
SimpleHexEditor.B_Update=Update
SysBotRAMEdit.B_Connect=Connect
SysBotRAMEdit.B_Edit=Edit
SysBotRAMEdit.GB_Inject=Injector
SysBotRAMEdit.L_IP=IP:
SysBotRAMEdit.L_Length=Length:
SysBotRAMEdit.L_Offset=Offset:
SysBotRAMEdit.L_Port=Port:
SysBotUI.B_Connect=Connect
SysBotUI.B_ReadCurrent=Read
SysBotUI.B_WriteCurrent=Write
SysBotUI.CHK_AutoRead=AutoRead
SysBotUI.CHK_AutoWrite=AutoWrite
SysBotUI.CHK_Validate=Validate Data
SysBotUI.GB_Inject=Injector
SysBotUI.L_IP=IP:
SysBotUI.L_Offset=Offset:
SysBotUI.L_Port=Port:
TerrainEditor.B_Cancel=Cancel
TerrainEditor.B_Down=↓
TerrainEditor.B_DumpAcre=Dump Acre
TerrainEditor.B_DumpAllAcres=Dump All Acres
TerrainEditor.B_ImportAcre=Import Acre
TerrainEditor.B_ImportAllAcres=Import All Acres
TerrainEditor.B_Left=←
TerrainEditor.B_Right=→
TerrainEditor.B_Save=Save
TerrainEditor.B_SetAll=Set All Tiles using Tile from Editor
TerrainEditor.B_Up=↑
TerrainEditor.B_ZeroElevation=Zero All Elevation
TerrainEditor.CHK_SnapToAcre=Snap to nearest Acre on Click
TerrainEditor.L_Acre=Acre:
TerrainEditor.Menu_SavePNG=Save .png

View File

@ -0,0 +1,142 @@
AcreEditor=Acre Editor
ActivityEditor=Record Editor
BuildingEditor=Building Editor
FieldItemEditor=Field Item Editor
FlagEditor=Flag Editor
ItemReceivedEditor=Received Item List Editor
SimpleHexEditor=RAM Edit
SysBotRAMEdit=SysBotUI
SysBotUI=SysBotUI
TerrainEditor=Terrain Editor
AcreEditor.B_Cancel=Cancel
AcreEditor.B_Export=Export
AcreEditor.B_Import=Import
AcreEditor.B_Save=Save
AcreEditor.L_AcreList=Name Table:
AcreEditor.L_Hovered=Hovered
ActivityEditor.B_Cancel=Cancel
ActivityEditor.B_Save=Save
ActivityEditor.L_Count=Count:
BuildingEditor.B_Cancel=Cancel
BuildingEditor.B_Dump=Dump
BuildingEditor.B_Import=Import
BuildingEditor.B_Save=Save
BuildingEditor.GB_Building=Editor
BuildingEditor.GB_Info=Info
BuildingEditor.L_Bit=Bit:
BuildingEditor.L_BuildingRotation=Angle:
BuildingEditor.L_BuildingStructureArg=TypeArg:
BuildingEditor.L_BuildingStructureType=Type:
BuildingEditor.L_BuildingType=Building Type:
BuildingEditor.L_BuildingUniqueID=UniqueID:
BuildingEditor.L_BuildingX=X:
BuildingEditor.L_BuildingY=Y:
BuildingEditor.L_PlazaX=Plaza X:
BuildingEditor.L_PlazaY=Plaza Y:
BuildingEditor.L_StructureType=Structure Type:
BuildingEditor.L_StructureValues=Values:
Editor.B_DumpDesign=Dump Design
Editor.B_DumpHouse=Dump House
Editor.B_EditAchievements=Edit Achievements
Editor.B_EditAcres=Edit Acres
Editor.B_EditBuildings=Edit Buildings
Editor.B_EditFieldItems=Edit Field Items
Editor.B_EditLandFlags=Edit Flags
Editor.B_EditPlayerFlags=Edit Flags
Editor.B_EditPlayerItems=Edit Items
Editor.B_EditPlayerReceivedItems=Edit Received Items
Editor.B_EditPlayerRecipes=Edit Recipes
Editor.B_EditPlayerStorage=Edit Storage
Editor.B_EditTerrain=Edit Terrain
Editor.B_EditTurnipExchange=Edit Turnip Exchange
Editor.B_LoadDesign=Load Design
Editor.B_LoadHouse=Load House
Editor.B_RecycleBin=Edit Recycle Bin
Editor.L_BankBells=Bank Bells:
Editor.L_NookMiles=Nook Miles:
Editor.L_PatternIndex=Design Index:
Editor.L_PatternName=*PatternName
Editor.L_PlayerHouse=Player House:
Editor.L_PlayerName=Player Name:
Editor.L_TownName=Town Name:
Editor.L_Wallet=Wallet:
Editor.Menu_DumpDecrypted=Dump Decrypted
Editor.Menu_File=File
Editor.Menu_LoadDecrypted=Load Decrypted
Editor.Menu_Options=Options
Editor.Menu_RAMEdit=RAM Edit
Editor.Menu_Save=Save
Editor.Menu_SavePNG=Save .png
Editor.Menu_Settings=Settings
Editor.Menu_Tools=Tools
Editor.Menu_VerifyHashes=Verify Hashes
Editor.Tab_Designs=Designs
Editor.Tab_Map=Map
Editor.Tab_Players=Players
Editor.Tab_Villagers=Villagers
FieldItemEditor.B_Cancel=Cancel
FieldItemEditor.B_Down=↓
FieldItemEditor.B_DumpAcre=Dump Acre
FieldItemEditor.B_DumpAllAcres=Dump All Acres
FieldItemEditor.B_FillHoles=Holes
FieldItemEditor.B_ImportAcre=Import Acre
FieldItemEditor.B_ImportAllAcres=Import All Acres
FieldItemEditor.B_Left=←
FieldItemEditor.B_RemoveAll=All
FieldItemEditor.B_RemoveAllWeeds=Weeds
FieldItemEditor.B_RemoveFences=Fences
FieldItemEditor.B_RemoveObjects=Non-Items
FieldItemEditor.B_RemovePlacedItems=Placed Items
FieldItemEditor.B_RemovePlants=Plants
FieldItemEditor.B_Right=→
FieldItemEditor.B_Save=Save
FieldItemEditor.B_Up=↑
FieldItemEditor.CHK_SnapToAcre=Snap to nearest Acre on Click
FieldItemEditor.GB_Remove=Remove from View (Hold Shift=Map)
FieldItemEditor.L_Acre=Acre:
FieldItemEditor.L_Layer=Layer:
FieldItemEditor.Menu_Reset=Reset
FieldItemEditor.Menu_SavePNG=Save .png
FieldItemEditor.Menu_Set=Set
FieldItemEditor.Menu_View=View
FlagEditor.B_Cancel=Cancel
FlagEditor.B_Save=Save
FlagEditor.L_Count=Value:
ItemReceivedEditor.B_AllBugs=Give All Bugs
ItemReceivedEditor.B_AllFish=Give All Fish
ItemReceivedEditor.B_Cancel=Cancel
ItemReceivedEditor.B_GiveAll=Give All
ItemReceivedEditor.B_Save=Save
SimpleHexEditor.B_Update=Update
SysBotRAMEdit.B_Connect=Connect
SysBotRAMEdit.B_Edit=Edit
SysBotRAMEdit.GB_Inject=Injector
SysBotRAMEdit.L_IP=IP:
SysBotRAMEdit.L_Length=Length:
SysBotRAMEdit.L_Offset=Offset:
SysBotRAMEdit.L_Port=Port:
SysBotUI.B_Connect=Connect
SysBotUI.B_ReadCurrent=Read
SysBotUI.B_WriteCurrent=Write
SysBotUI.CHK_AutoRead=AutoRead
SysBotUI.CHK_AutoWrite=AutoWrite
SysBotUI.CHK_Validate=Validate Data
SysBotUI.GB_Inject=Injector
SysBotUI.L_IP=IP:
SysBotUI.L_Offset=Offset:
SysBotUI.L_Port=Port:
TerrainEditor.B_Cancel=Cancel
TerrainEditor.B_Down=↓
TerrainEditor.B_DumpAcre=Dump Acre
TerrainEditor.B_DumpAllAcres=Dump All Acres
TerrainEditor.B_ImportAcre=Import Acre
TerrainEditor.B_ImportAllAcres=Import All Acres
TerrainEditor.B_Left=←
TerrainEditor.B_Right=→
TerrainEditor.B_Save=Save
TerrainEditor.B_SetAll=Set All Tiles using Tile from Editor
TerrainEditor.B_Up=↑
TerrainEditor.B_ZeroElevation=Zero All Elevation
TerrainEditor.CHK_SnapToAcre=Snap to nearest Acre on Click
TerrainEditor.L_Acre=Acre:
TerrainEditor.Menu_SavePNG=Save .png

View File

@ -0,0 +1,142 @@
AcreEditor=Acre Editor
ActivityEditor=Record Editor
BuildingEditor=Building Editor
FieldItemEditor=Field Item Editor
FlagEditor=Flag Editor
ItemReceivedEditor=Received Item List Editor
SimpleHexEditor=RAM Edit
SysBotRAMEdit=SysBotUI
SysBotUI=SysBotUI
TerrainEditor=Terrain Editor
AcreEditor.B_Cancel=Cancel
AcreEditor.B_Export=Export
AcreEditor.B_Import=Import
AcreEditor.B_Save=Save
AcreEditor.L_AcreList=Name Table:
AcreEditor.L_Hovered=Hovered
ActivityEditor.B_Cancel=Cancel
ActivityEditor.B_Save=Save
ActivityEditor.L_Count=Count:
BuildingEditor.B_Cancel=Cancel
BuildingEditor.B_Dump=Dump
BuildingEditor.B_Import=Import
BuildingEditor.B_Save=Save
BuildingEditor.GB_Building=Editor
BuildingEditor.GB_Info=Info
BuildingEditor.L_Bit=Bit:
BuildingEditor.L_BuildingRotation=Angle:
BuildingEditor.L_BuildingStructureArg=TypeArg:
BuildingEditor.L_BuildingStructureType=Type:
BuildingEditor.L_BuildingType=Building Type:
BuildingEditor.L_BuildingUniqueID=UniqueID:
BuildingEditor.L_BuildingX=X:
BuildingEditor.L_BuildingY=Y:
BuildingEditor.L_PlazaX=Plaza X:
BuildingEditor.L_PlazaY=Plaza Y:
BuildingEditor.L_StructureType=Structure Type:
BuildingEditor.L_StructureValues=Values:
Editor.B_DumpDesign=Dump Design
Editor.B_DumpHouse=Dump House
Editor.B_EditAchievements=Edit Achievements
Editor.B_EditAcres=Edit Acres
Editor.B_EditBuildings=Edit Buildings
Editor.B_EditFieldItems=Edit Field Items
Editor.B_EditLandFlags=Edit Flags
Editor.B_EditPlayerFlags=Edit Flags
Editor.B_EditPlayerItems=Edit Items
Editor.B_EditPlayerReceivedItems=Edit Received Items
Editor.B_EditPlayerRecipes=Edit Recipes
Editor.B_EditPlayerStorage=Edit Storage
Editor.B_EditTerrain=Edit Terrain
Editor.B_EditTurnipExchange=Edit Turnip Exchange
Editor.B_LoadDesign=Load Design
Editor.B_LoadHouse=Load House
Editor.B_RecycleBin=Edit Recycle Bin
Editor.L_BankBells=Bank Bells:
Editor.L_NookMiles=Nook Miles:
Editor.L_PatternIndex=Design Index:
Editor.L_PatternName=*PatternName
Editor.L_PlayerHouse=Player House:
Editor.L_PlayerName=Player Name:
Editor.L_TownName=Town Name:
Editor.L_Wallet=Wallet:
Editor.Menu_DumpDecrypted=Dump Decrypted
Editor.Menu_File=File
Editor.Menu_LoadDecrypted=Load Decrypted
Editor.Menu_Options=Options
Editor.Menu_RAMEdit=RAM Edit
Editor.Menu_Save=Save
Editor.Menu_SavePNG=Save .png
Editor.Menu_Settings=Settings
Editor.Menu_Tools=Tools
Editor.Menu_VerifyHashes=Verify Hashes
Editor.Tab_Designs=Designs
Editor.Tab_Map=Map
Editor.Tab_Players=Players
Editor.Tab_Villagers=Villagers
FieldItemEditor.B_Cancel=Cancel
FieldItemEditor.B_Down=↓
FieldItemEditor.B_DumpAcre=Dump Acre
FieldItemEditor.B_DumpAllAcres=Dump All Acres
FieldItemEditor.B_FillHoles=Holes
FieldItemEditor.B_ImportAcre=Import Acre
FieldItemEditor.B_ImportAllAcres=Import All Acres
FieldItemEditor.B_Left=←
FieldItemEditor.B_RemoveAll=All
FieldItemEditor.B_RemoveAllWeeds=Weeds
FieldItemEditor.B_RemoveFences=Fences
FieldItemEditor.B_RemoveObjects=Non-Items
FieldItemEditor.B_RemovePlacedItems=Placed Items
FieldItemEditor.B_RemovePlants=Plants
FieldItemEditor.B_Right=→
FieldItemEditor.B_Save=Save
FieldItemEditor.B_Up=↑
FieldItemEditor.CHK_SnapToAcre=Snap to nearest Acre on Click
FieldItemEditor.GB_Remove=Remove from View (Hold Shift=Map)
FieldItemEditor.L_Acre=Acre:
FieldItemEditor.L_Layer=Layer:
FieldItemEditor.Menu_Reset=Reset
FieldItemEditor.Menu_SavePNG=Save .png
FieldItemEditor.Menu_Set=Set
FieldItemEditor.Menu_View=View
FlagEditor.B_Cancel=Cancel
FlagEditor.B_Save=Save
FlagEditor.L_Count=Value:
ItemReceivedEditor.B_AllBugs=Give All Bugs
ItemReceivedEditor.B_AllFish=Give All Fish
ItemReceivedEditor.B_Cancel=Cancel
ItemReceivedEditor.B_GiveAll=Give All
ItemReceivedEditor.B_Save=Save
SimpleHexEditor.B_Update=Update
SysBotRAMEdit.B_Connect=Connect
SysBotRAMEdit.B_Edit=Edit
SysBotRAMEdit.GB_Inject=Injector
SysBotRAMEdit.L_IP=IP:
SysBotRAMEdit.L_Length=Length:
SysBotRAMEdit.L_Offset=Offset:
SysBotRAMEdit.L_Port=Port:
SysBotUI.B_Connect=Connect
SysBotUI.B_ReadCurrent=Read
SysBotUI.B_WriteCurrent=Write
SysBotUI.CHK_AutoRead=AutoRead
SysBotUI.CHK_AutoWrite=AutoWrite
SysBotUI.CHK_Validate=Validate Data
SysBotUI.GB_Inject=Injector
SysBotUI.L_IP=IP:
SysBotUI.L_Offset=Offset:
SysBotUI.L_Port=Port:
TerrainEditor.B_Cancel=Cancel
TerrainEditor.B_Down=↓
TerrainEditor.B_DumpAcre=Dump Acre
TerrainEditor.B_DumpAllAcres=Dump All Acres
TerrainEditor.B_ImportAcre=Import Acre
TerrainEditor.B_ImportAllAcres=Import All Acres
TerrainEditor.B_Left=←
TerrainEditor.B_Right=→
TerrainEditor.B_Save=Save
TerrainEditor.B_SetAll=Set All Tiles using Tile from Editor
TerrainEditor.B_Up=↑
TerrainEditor.B_ZeroElevation=Zero All Elevation
TerrainEditor.CHK_SnapToAcre=Snap to nearest Acre on Click
TerrainEditor.L_Acre=Acre:
TerrainEditor.Menu_SavePNG=Save .png

View File

@ -14,6 +14,7 @@ public partial class AcreEditor : Form
public AcreEditor(MainSave sav)
{
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
SAV = sav;
Acres = new[]

View File

@ -17,6 +17,7 @@ public partial class BuildingEditor : Form
public BuildingEditor(IReadOnlyList<Building> buildings, MainSave sav)
{
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
SAV = sav;
Buildings = buildings;
Terrain = new TerrainManager(sav.GetTerrain());

View File

@ -54,7 +54,7 @@ private void InitializeComponent()
this.CHK_SnapToAcre = new System.Windows.Forms.CheckBox();
this.L_Coordinates = new System.Windows.Forms.Label();
this.NUD_Layer = new System.Windows.Forms.NumericUpDown();
this.label1 = new System.Windows.Forms.Label();
this.L_Layer = new System.Windows.Forms.Label();
this.TT_Hover = new System.Windows.Forms.ToolTip(this.components);
this.PB_Acre = new System.Windows.Forms.PictureBox();
this.B_RemoveAllWeeds = new System.Windows.Forms.Button();
@ -309,14 +309,14 @@ private void InitializeComponent()
0});
this.NUD_Layer.ValueChanged += new System.EventHandler(this.NUD_Layer_ValueChanged);
//
// label1
// L_Layer
//
this.label1.Location = new System.Drawing.Point(632, 365);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(53, 19);
this.label1.TabIndex = 27;
this.label1.Text = "Layer:";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
this.L_Layer.Location = new System.Drawing.Point(632, 365);
this.L_Layer.Name = "L_Layer";
this.L_Layer.Size = new System.Drawing.Size(53, 19);
this.L_Layer.TabIndex = 27;
this.L_Layer.Text = "Layer:";
this.L_Layer.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// TT_Hover
//
@ -427,7 +427,7 @@ private void InitializeComponent()
this.ClientSize = new System.Drawing.Size(981, 537);
this.Controls.Add(this.GB_Remove);
this.Controls.Add(this.PB_Acre);
this.Controls.Add(this.label1);
this.Controls.Add(this.L_Layer);
this.Controls.Add(this.NUD_Layer);
this.Controls.Add(this.L_Coordinates);
this.Controls.Add(this.CHK_SnapToAcre);
@ -488,7 +488,7 @@ private void InitializeComponent()
private System.Windows.Forms.CheckBox CHK_SnapToAcre;
private System.Windows.Forms.Label L_Coordinates;
private System.Windows.Forms.NumericUpDown NUD_Layer;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label L_Layer;
private System.Windows.Forms.ToolTip TT_Hover;
private System.Windows.Forms.PictureBox PB_Acre;
private System.Windows.Forms.Button B_RemoveAllWeeds;

View File

@ -29,9 +29,10 @@ public partial class FieldItemEditor : Form
public FieldItemEditor(MainSave sav)
{
SAV = sav;
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
SAV = sav;
Items = new FieldItemManager(SAV.GetFieldItems());
var l1 = Items.Layer1;

View File

@ -10,8 +10,10 @@ public partial class LandFlagEditor : Form
public LandFlagEditor(short[] counts)
{
Counts = counts;
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
Counts = counts;
for (ushort i = 0; i < counts.Length; i++)
LB_Counts.Items.Add(EventFlagLand.GetFlagName(i, counts[i]));
DialogResult = DialogResult.Cancel;

View File

@ -22,9 +22,10 @@ public partial class TerrainEditor : Form
public TerrainEditor(MainSave sav)
{
SAV = sav;
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
SAV = sav;
Terrain = new TerrainManager(SAV.GetTerrain());
Grid = GenerateGrid(GridWidth, GridHeight);

View File

@ -12,6 +12,7 @@ public AchievementEditor(uint[] counts)
{
Counts = counts;
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
for (int i = 0; i < counts.Length; i++)
LB_Counts.Items.Add(LifeSupportAchievement.GetName(i, counts[i]));
DialogResult = DialogResult.Cancel;

View File

@ -12,6 +12,7 @@ public FlagEditor(short[] counts)
{
Counts = counts;
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
for (ushort i = 0; i < counts.Length; i++)
LB_Counts.Items.Add(EventFlagPlayer.GetFlagName(i, counts[i]));
DialogResult = DialogResult.Cancel;

View File

@ -13,6 +13,7 @@ public ItemReceivedEditor(Player player)
{
Player = player;
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
FillCheckBoxes();
Initialize(GameInfo.Strings.ItemDataSource);
CLB_Items.SelectedIndex = 0x50;

View File

@ -16,6 +16,7 @@ public RecipeListEditor(Player player)
Player = player;
Known = Player.Personal.GetRecipeList();
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
var gotoSource = FillCheckBoxes();
gotoSource.SortByText();

View File

@ -17,6 +17,7 @@ public partial class PlayerItemEditor<T> : Form where T : Item
public PlayerItemEditor(IReadOnlyList<T> array, int width, int height, bool sysbot = false)
{
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
Items = array;
var Editor = ItemGrid = new ItemGridEditor(ItemEditor, Items) {Dock = DockStyle.Fill};

View File

@ -13,6 +13,7 @@ public partial class PropertyEditor<T> : Form where T : INamedObject
public PropertyEditor(IReadOnlyList<T> objects, IReadOnlyList<string> names)
{
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
Objects = objects;
Names = names;
DialogResult = DialogResult.Cancel;

View File

@ -1,5 +1,6 @@
using System;
using System.Windows.Forms;
using NHSE.Core;
namespace NHSE.WinForms
{
@ -8,6 +9,7 @@ public partial class SingleObjectEditor<T> : Form where T : class
public SingleObjectEditor(T obj, PropertySort sort)
{
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
DialogResult = DialogResult.Cancel;
PG_Item.PropertySort = sort;
PG_Item.SelectedObject = obj;

View File

@ -1,5 +1,6 @@
using System.Linq;
using System.Windows.Forms;
using NHSE.Core;
using NHSE.Injection;
namespace NHSE.WinForms
@ -11,6 +12,7 @@ public partial class SimpleHexEditor : Form
public SimpleHexEditor(byte[] originalBytes)
{
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
RTB_RAM.Text = string.Join(" ", originalBytes.Select(z => $"{z:X2}"));
Bytes = originalBytes;
}

View File

@ -12,6 +12,7 @@ public partial class SysBotRAMEdit : Form
public SysBotRAMEdit(InjectionType type)
{
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
Bot = new SysBotController(type);
RamOffset.Text = Bot.GetDefaultOffset().ToString("X8");

View File

@ -13,6 +13,7 @@ public partial class SysBotUI : Form
public SysBotUI(AutoInjector injector, SysBotController c)
{
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
Bot = c;
Injector = injector;

View File

@ -12,6 +12,7 @@ public VillagerFlagEditor(ushort[] counts)
{
Counts = counts;
InitializeComponent();
this.TranslateInterface(GameInfo.CurrentLanguage);
for (ushort i = 0; i < counts.Length; i++)
LB_Counts.Items.Add(EventFlagVillager.GetFlagName(i, counts[i]));
DialogResult = DialogResult.Cancel;

View File

@ -0,0 +1,116 @@
using System;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using NHSE.Core;
namespace NHSE.WinForms
{
#if DEBUG
public static class DevUtil
{
private static readonly string[] Languages = { "jp", "zh" };
private const string DefaultLanguage = GameLanguage.DefaultLanguage;
public static bool IsUpdatingTranslations { get; private set; }
/// <summary>
/// Call this to update all translatable resources (Program Messages, Legality Text, Program GUI)
/// </summary>
public static void UpdateAll()
{
if (DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Update translation files with current values?"))
return;
IsUpdatingTranslations = true;
DumpStringsMessage();
UpdateTranslations();
IsUpdatingTranslations = false;
}
private static void UpdateTranslations()
{
WinFormsTranslator.SetRemovalMode(false); // add mode
WinFormsTranslator.LoadAllForms(LoadBanlist); // populate with every possible control
WinFormsTranslator.UpdateAll(DefaultLanguage, Languages); // propagate to others
WinFormsTranslator.DumpAll(Banlist); // dump current to file
WinFormsTranslator.SetRemovalMode(); // remove used keys, don't add any
WinFormsTranslator.LoadAllForms(LoadBanlist); // de-populate
WinFormsTranslator.RemoveAll(DefaultLanguage, PurgeBanlist); // remove all lines from above generated files that still remain
// Move translated files from the debug exe loc to their project location
var files = Directory.GetFiles(Application.StartupPath);
var dir = GetResourcePath().Replace("NHSE.Core", "NHSE.WinForms");
foreach (var f in files)
{
var fn = Path.GetFileName(f);
if (!fn.EndsWith(".txt"))
continue;
if (!fn.StartsWith("lang_"))
continue;
var loc = Path.Combine(dir, fn);
if (File.Exists(loc))
File.Delete(loc);
File.Move(f, loc);
}
Application.Exit();
}
private static readonly string[] LoadBanlist =
{
nameof(SettingsEditor),
};
private static readonly string[] Banlist =
{
"Editor=NHSE", // Program Title
"InternalName=",
"ExternalName=",
"AcreEditor.L_X",
"AcreEditor.L_Y",
"L_Coordinates",
};
private static readonly string[] PurgeBanlist =
{
nameof(SettingsEditor),
};
private static void DumpStringsMessage() => DumpStrings(typeof(MessageStrings));
private static void DumpStrings(Type t)
{
var dir = GetResourcePath();
var langs = new[] { DefaultLanguage }.Concat(Languages);
foreach (var lang in langs)
{
TranslationUtil.SetLocalization(t, lang);
var entries = TranslationUtil.GetLocalization(t);
var location = GetFileLocationInText(t.Name, dir, lang);
File.WriteAllLines(location, entries);
TranslationUtil.SetLocalization(t, DefaultLanguage);
}
}
private static string GetFileLocationInText(string fileType, string dir, string lang)
{
var path = Path.Combine(dir, lang);
if (!Directory.Exists(path))
path = Path.Combine(dir, "other");
var fn = $"{fileType}_{lang}.txt";
return Path.Combine(path, fn);
}
private static string GetResourcePath()
{
var path = Application.StartupPath;
const string projname = "NHSE\\";
var pos = path.LastIndexOf(projname, StringComparison.Ordinal);
var str = path.Substring(0, pos + projname.Length);
return Path.Combine(str, "NHSE.Core", "Resources", "text");
}
}
#endif
}

View File

@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using NHSE.Core;
namespace NHSE.WinForms
{
public static class TranslationUtil
{
private const char TranslationSplitter = '=';
/// <summary>
/// Gets the names of the properties defined in the given input
/// </summary>
/// <param name="input">Enumerable of translation definitions in the form "Property = Value".</param>
private static string[] GetProperties(IEnumerable<string> input)
{
return input.Select(l => l.Substring(0, l.IndexOf(TranslationSplitter)))
.ToArray();
}
private static IEnumerable<string> DumpStrings(Type t)
{
var props = ReflectUtil.GetPropertiesStartWithPrefix(t, string.Empty);
return props.Select(p => $"{p}{TranslationSplitter}{ReflectUtil.GetValue(t, p)}");
}
/// <summary>
/// Gets the current localization in a static class containing language-specific strings
/// </summary>
/// <param name="t"></param>
public static string[] GetLocalization(Type t) => DumpStrings(t).ToArray();
/// <summary>
/// Gets the current localization in a static class containing language-specific strings
/// </summary>
/// <param name="t"></param>
/// <param name="existingLines">Existing localization lines (if provided)</param>
public static string[] GetLocalization(Type t, string[] existingLines)
{
var currentLines = GetLocalization(t);
var existing = GetProperties(existingLines);
var current = GetProperties(currentLines);
var result = new string[currentLines.Length];
for (int i = 0; i < current.Length; i++)
{
int index = Array.IndexOf(existing, current[i]);
result[i] = index < 0 ? currentLines[i] : existingLines[index];
}
return result;
}
/// <summary>
/// Applies localization to a static class containing language-specific strings.
/// </summary>
/// <param name="t">Type of the static class containing the desired strings.</param>
/// <param name="lines">Lines containing the localized strings</param>
private static void SetLocalization(Type t, IReadOnlyCollection<string> lines)
{
if (lines.Count == 0)
return;
foreach (var line in lines)
{
var index = line.IndexOf(TranslationSplitter);
if (index < 0)
continue;
var prop = line.Substring(0, index);
var value = line.Substring(index + 1);
try
{
ReflectUtil.SetValue(t, prop, value);
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception e)
#pragma warning restore CA1031 // Do not catch general exception types
{
Debug.WriteLine($"Property not present: {prop} || Value written: {value}");
Debug.WriteLine(e.Message);
}
}
}
/// <summary>
/// Applies localization to a static class containing language-specific strings.
/// </summary>
/// <param name="t">Type of the static class containing the desired strings.</param>
/// <param name="languageFilePrefix">Prefix of the language file to use. Example: if the target is legality_en.txt, <paramref name="languageFilePrefix"/> should be "legality".</param>
/// <param name="currentCultureCode">Culture information</param>
private static void SetLocalization(Type t, string languageFilePrefix, string currentCultureCode)
{
SetLocalization(t, ResourceUtil.GetStringList($"{languageFilePrefix}_{currentCultureCode}"));
}
/// <summary>
/// Applies localization to a static class containing language-specific strings.
/// </summary>
/// <param name="t">Type of the static class containing the desired strings.</param>
/// <remarks>The values used to translate the given static class are retrieved from [TypeName]_[CurrentLangCode2].txt in the resource manager of NHSE.Core.</remarks>
/// <param name="currentCultureCode">Culture information</param>
public static void SetLocalization(Type t, string currentCultureCode)
{
SetLocalization(t, t.Name, currentCultureCode);
}
}
}

View File

@ -0,0 +1,273 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using NHSE.Core;
namespace NHSE.WinForms
{
public static class WinFormsTranslator
{
private static readonly Dictionary<string, TranslationContext> Context = new Dictionary<string, TranslationContext>();
internal static void TranslateInterface(this Control form, string lang) => TranslateForm(form, GetContext(lang));
private static string GetTranslationFileNameInternal(string lang) => $"lang_{lang}";
private static string GetTranslationFileNameExternal(string lang) => $"lang_{lang}.txt";
private static TranslationContext GetContext(string lang)
{
if (Context.TryGetValue(lang, out var context))
return context;
var lines = GetTranslationFile(lang);
Context.Add(lang, context = new TranslationContext(lines));
return context;
}
private static void TranslateForm(Control form, TranslationContext context)
{
form.SuspendLayout();
var formname = form.Name;
// Translate Title
form.Text = context.GetTranslatedText(formname, form.Text);
var translatable = GetTranslatableControls(form);
foreach (var c in translatable)
{
if (c is Control r)
{
var current = r.Text;
var updated = context.GetTranslatedText($"{formname}.{r.Name}", current);
if (!ReferenceEquals(current, updated))
r.Text = updated;
}
else if (c is ToolStripItem t)
{
var current = t.Text;
var updated = context.GetTranslatedText($"{formname}.{t.Name}", current);
if (!ReferenceEquals(current, updated))
t.Text = updated;
}
}
form.ResumeLayout();
}
private static IEnumerable<string> GetTranslationFile(string lang)
{
var file = GetTranslationFileNameInternal(lang);
// Check to see if a the translation file exists in the same folder as the executable
string externalLangPath = GetTranslationFileNameExternal(file);
if (File.Exists(externalLangPath))
{
try
{
return File.ReadAllLines(externalLangPath);
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception e)
#pragma warning restore CA1031 // Do not catch general exception types
{
/* In use? Just return the internal resource. */
Console.WriteLine(e.Message);
}
}
if (ResourceUtil.IsStringListCached(file, out var result))
return result;
var obj = Properties.Resources.ResourceManager.GetObject(file);
if (!(obj is string txt))
return Array.Empty<string>();
return ResourceUtil.LoadStringList(file, txt);
}
private static IEnumerable<object> GetTranslatableControls(Control f)
{
foreach (var z in f.GetChildrenOfType<Control>())
{
switch (z)
{
case ToolStrip menu:
foreach (var obj in GetToolStripMenuItems(menu))
yield return obj;
break;
default:
if (string.IsNullOrWhiteSpace(z.Name))
break;
if (z.ContextMenuStrip != null) // control has attached menustrip
{
foreach (var obj in GetToolStripMenuItems(z.ContextMenuStrip))
yield return obj;
}
if (z is ListControl || z is TextBoxBase || z is LinkLabel || z is NumericUpDown || z is ContainerControl)
break; // undesirable to modify, ignore
if (!string.IsNullOrWhiteSpace(z.Text))
yield return z;
break;
}
}
}
private static IEnumerable<T> GetChildrenOfType<T>(this Control control) where T : class
{
foreach (var child in control.Controls.OfType<Control>())
{
if (child is T childOfT)
yield return childOfT;
if (!child.HasChildren)
continue;
foreach (var descendant in GetChildrenOfType<T>(child))
yield return descendant;
}
}
private static IEnumerable<object> GetToolStripMenuItems(ToolStrip menu)
{
foreach (var i in menu.Items.OfType<ToolStripMenuItem>())
{
if (!string.IsNullOrWhiteSpace(i.Text))
yield return i;
foreach (var sub in GetToolsStripDropDownItems(i).Where(z => !string.IsNullOrWhiteSpace(z.Text)))
yield return sub;
}
}
private static IEnumerable<ToolStripMenuItem> GetToolsStripDropDownItems(ToolStripDropDownItem item)
{
foreach (var dropDownItem in item.DropDownItems.OfType<ToolStripMenuItem>())
{
yield return dropDownItem;
if (!dropDownItem.HasDropDownItems) continue;
foreach (ToolStripMenuItem subItem in GetToolsStripDropDownItems(dropDownItem))
yield return subItem;
}
}
public static void UpdateAll(string baseLanguage, IEnumerable<string> others)
{
var basecontext = GetContext(baseLanguage);
foreach (var lang in others)
{
var c = GetContext(lang);
c.UpdateFrom(basecontext);
}
}
public static void DumpAll(params string[] banlist)
{
var results = Context.Select(z => new { Lang = z.Key, Lines = z.Value.Write() });
foreach (var c in results)
{
var lang = c.Lang;
var fn = GetTranslationFileNameExternal(lang);
var lines = c.Lines;
var result = lines.Where(z => !banlist.Any(z.Contains));
File.WriteAllLines(fn, result);
}
}
public static void LoadAllForms(params string[] banlist)
{
var q = from t in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
where t.BaseType == typeof(Form) && !banlist.Contains(t.Name)
select t;
foreach (var t in q)
{
var constructors = t.GetConstructors();
if (constructors.Length == 0)
{
Console.WriteLine($"No constructors: {t.Name}");
continue;
}
var argCount = constructors[0].GetParameters().Length;
try
{
var _ = Activator.CreateInstance(t, new object[argCount]);
}
#pragma warning disable CA1031 // Do not catch general exception types
catch
#pragma warning restore CA1031 // Do not catch general exception types
{
// ignored
}
}
}
public static void SetRemovalMode(bool status = true)
{
foreach (TranslationContext c in Context.Values)
{
c.RemoveUsedKeys = status;
c.AddNew = !status;
}
}
public static void RemoveAll(string defaultLanguage, params string[] banlist)
{
var badKeys = Context[defaultLanguage];
var split = badKeys.Write().Select(z => z.Split(TranslationContext.Separator)[0])
.Where(l => !banlist.Any(l.StartsWith)).ToArray();
foreach (var c in Context)
{
var lang = c.Key;
var fn = GetTranslationFileNameExternal(lang);
var lines = File.ReadAllLines(fn);
var result = lines.Where(l => !split.Any(s => l.StartsWith(s + TranslationContext.Separator)));
File.WriteAllLines(fn, result);
}
}
}
public sealed class TranslationContext
{
public bool AddNew { private get; set; }
public bool RemoveUsedKeys { private get; set; }
public const char Separator = '=';
private readonly Dictionary<string, string> Translation = new Dictionary<string, string>();
public TranslationContext(IEnumerable<string> content, char separator = Separator)
{
var entries = content.Select(z => z.Split(separator)).Where(z => z.Length == 2);
foreach (var kvp in entries.Where(z => !Translation.ContainsKey(z[0])))
Translation.Add(kvp[0], kvp[1]);
}
public string GetTranslatedText(string val, string fallback)
{
if (RemoveUsedKeys)
Translation.Remove(val);
if (Translation.TryGetValue(val, out var translated))
return translated;
if (AddNew)
Translation.Add(val, fallback);
return fallback;
}
public IEnumerable<string> Write(char separator = Separator)
{
return Translation.Select(z => $"{z.Key}{separator}{z.Value}").OrderBy(z => z.Contains(".")).ThenBy(z => z);
}
public void UpdateFrom(TranslationContext other)
{
bool oldAdd = AddNew;
AddNew = true;
foreach (var kvp in other.Translation)
GetTranslatedText(kvp.Key, kvp.Value);
AddNew = oldAdd;
}
public void RemoveKeys(TranslationContext other)
{
foreach (var kvp in other.Translation)
Translation.Remove(kvp.Key);
}
}
}

View File

@ -6,6 +6,8 @@ namespace NHSE.WinForms
{
internal static class WinFormsUtil
{
internal static void TranslateInterface(Control form, string lang) => form.TranslateInterface(lang);
#region Message Displays
/// <summary>
/// Displays a dialog showing the details of an error.