LoginSignup
0
1

More than 1 year has passed since last update.

【2022年】PowerShellでExcelからAndroidのstrings.xmlを自動生成する

Last updated at Posted at 2022-07-19

前置き

この最後で紹介した、「翻訳用の文字列を列挙したExcel」から
自動でstrings.xmlを作成するというので
実際どう作ればいいのかというのをPowershellを使って実装してみる

なぜPowerShellなのか

まぁExcel読み込んでテキストファイル吐き出せれば
C#でもPythonでもBrainFuckでもぶっちゃけなんでもいいんだけど
PowerShellはデフォルトでWindowsに搭載されてて
余計な物やエディタをインストールする必要ないので、これがお手軽かなと
macとかは知らん。Python使えばいいんじゃない?(適当)

エディタはサクラエディタ使ってる
(batファイルがctrl+Bで実行できるので)

ファイル構成

LangFileConverterというフォルダを作り、この階層にbatやps1や翻訳用excelをぶち込む

image.png

※)hello.ps1はテストで使ったゴミです

想定する翻訳Excel

・app sheet

image.png

・system sheet
image.png

・npc sheet
image.png

・item sheet
image.png

execute.bat

make_strings_xml.ps1 を実行するための叩き台

execute.bat
PowerShell -ExecutionPolicy RemoteSigned .\make_strings_xml.ps1
pause

make_strings_xml.ps1

まずは全体の処理

make_strings_xml.ps1
# 1つのIDに対する言語データ
class Data
{
	[string] $name
	[string] $jp
	[string] $en
}

# データのリスト
$data_list = New-Object 'System.Collections.Generic.List[Data]'

# 1枚分のシートを読み込む
function ReadSheet( $sheet )
{
	# 最終行を取得
	$lastRowIndex = $sheet.UsedRange.Rows.Count + 1
	
	# 1行目は無視する
	for ($i=2; $i -lt $lastRowIndex; $i++)
	{
		$id_string = $sheet.name + "_" + $sheet.Cells.Item($i, 1).Text
		
		$data = New-Object Data
		
		$data.name = $id_string
		$data.jp = $sheet.Cells.Item($i, 2).Text
		$data.en = $sheet.Cells.Item($i, 3).Text
		
		$data_list.Add($data)
	}

	
}

# Excel 読み込み処理
function ReadExcel()
{
	$excel = New-Object -ComObject Excel.Application
	$book = $null

	# 対象となるエクセルの絶対パス
	$excel_path = "C:\Users\h\Desktop\LangFileConverter\strings.xlsx"

	try
	{
		$excel.Visible = $false
	    $excel.DisplayAlerts = $false

		# エクセルを開く
	    $book = $excel.Workbooks.Open($excel_path)
	    
	    # シートの数だけ処理する
	    foreach($sheet in $book.Worksheets)
		{
	    	ReadSheet $sheet
		} 
	    
	} finally {
	    if ($book -ne $null) {
	        [void]$book.Close($false)
	        [System.Runtime.Interopservices.Marshal]::ReleaseComObject($book)
	    }

	    # Excelの終了
	    [void]$excel.Quit()

	    # オブジェクトの開放
	    # ApplicationとBookに対して行えばよい
	    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)
	}

}

# xml掃き出し処理
function OutputXml()
{
	$text_path = "C:\Users\h\Desktop\LangFileConverter\strings.xml"
	
	$output = "<resources>`r`n"
	
	# xml生成
	
	foreach( $d in $data_list )
	{
		$output += "`t<string-array name=`"$($d.name)`">`r`n"
		
		
			$output += "`t`t<item>$($d.jp)</item>`r`n"
			$output += "`t`t<item>$($d.en)</item>`r`n"
		
		
		$output += "`t</string-array>`r`n"
	}
	
	$output += "</resources>"
	
	#書き出し
	Write-Output ( $output | Out-File $text_path -Encoding default )
	
}

# 実行処理
ReadExcel
OutputXml

一応やろうと思えばオブジェクト指向っぽくかけるとは思うけど
スクリプト言語なので、スクリプト言語っぽく上から下に書きました

make_strings_xml.ps1
# 1つのIDに対する言語データ
class Data
{
	[string] $name
	[string] $jp
	[string] $en
}

# データのリスト
$data_list = New-Object 'System.Collections.Generic.List[Data]'

エクセルそのままでは使いづらいので
使いやすいようにデータ加工するためのクラスとリスト

make_strings_xml.ps1
# Excel 読み込み処理
function ReadExcel()
{
	$excel = New-Object -ComObject Excel.Application
	$book = $null

	# 対象となるエクセルの絶対パス
	$excel_path = "C:\Users\h\Desktop\LangFileConverter\strings.xlsx"

	try
	{
		$excel.Visible = $false
	    $excel.DisplayAlerts = $false

		# エクセルを開く
	    $book = $excel.Workbooks.Open($excel_path)
	    
	    # シートの数だけ処理する
	    foreach($sheet in $book.Worksheets)
		{
	    	ReadSheet $sheet
		} 
	    
	} finally {
	    if ($book -ne $null) {
	        [void]$book.Close($false)
	        [System.Runtime.Interopservices.Marshal]::ReleaseComObject($book)
	    }

	    # Excelの終了
	    [void]$excel.Quit()

	    # オブジェクトの開放
	    # ApplicationとBookに対して行えばよい
	    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)
	}

}

エクセルを読み込む処理
シートが複数あるので、シート単体への処理を別関数に分ける

make_strings_xml.ps1
# 1枚分のシートを読み込む
function ReadSheet( $sheet )
{
	# 最終行を取得
	$lastRowIndex = $sheet.UsedRange.Rows.Count + 1
	
	# 1行目は無視する
	for ($i=2; $i -lt $lastRowIndex; $i++)
	{
		$id_string = $sheet.name + "_" + $sheet.Cells.Item($i, 1).Text
		
		$data = New-Object Data
		
		$data.name = $id_string
		$data.jp = $sheet.Cells.Item($i, 2).Text
		$data.en = $sheet.Cells.Item($i, 3).Text
		
		$data_list.Add($data)
	}
}

1枚分のシートを読み込み、DataのListに変換する処理

make_strings_xml.ps1
# xml掃き出し処理
function OutputXml()
{
	$text_path = "C:\Users\h\Desktop\LangFileConverter\strings.xml"
	
	$output = "<resources>`r`n"
	
	# xml生成
	
	foreach( $d in $data_list )
	{
		$output += "`t<string-array name=`"$($d.name)`">`r`n"
		
		
			$output += "`t`t<item>$($d.jp)</item>`r`n"
			$output += "`t`t<item>$($d.en)</item>`r`n"
		
		
		$output += "`t</string-array>`r`n"
	}
	
	$output += "</resources>"
	
	#書き出し
	Write-Output ( $output | Out-File $text_path -Encoding default )
	
}

xmlを吐き出す処理
アプリによっては、xmlではなく、別の形式で文字列を管理する場合もあるので
どういう形式を求めるかによって、ここの処理は別物になると思う

xml形式以外で考えられるのは
C#やJavaとかで「nameをキーにしたDictionary」形式や
json形式での保存とか(webとかで使うのか?そっち方面の知識はない)
toml形式とかもアリかもしれない

実際に吐き出されたxml

strings.xml
<resources>
	<string-array name="app_name">
		<item>テストアプリケーション</item>
		<item>Test Application</item>
	</string-array>
	<string-array name="system_use_item">
		<item>{user}は{itemName}を使った</item>
		<item>The {user} used {itemName}.</item>
	</string-array>
	<string-array name="system_use_item_on_target">
		<item>{user}は{target}に{itemName}を使った</item>
		<item>The {user} used {itemName} on {target}.</item>
	</string-array>
	<string-array name="system_player_die">
		<item>{player}は力尽きた</item>
		<item>The {player} ran out of steam.</item>
	</string-array>
	<string-array name="npc_tadokoro_koji">
		<item>田所浩二</item>
		<item>Koji Tadokoro</item>
	</string-array>
	<string-array name="npc_hasegawa_ryota">
		<item>長谷川亮太</item>
		<item>Ryota Hasegawa</item>
	</string-array>
	<string-array name="npc_karasawa_takahiro">
		<item>唐澤貴洋</item>
		<item>Takahiro Karasawa</item>
	</string-array>
	<string-array name="npc_iwama_koiti">
		<item>岩間好一</item>
		<item>Yosikazu Iwama</item>
	</string-array>
	<string-array name="item_harb">
		<item>おハーブ</item>
		<item>herb</item>
	</string-array>
	<string-array name="item_portion">
		<item>ポーション</item>
		<item>portion</item>
	</string-array>
</resources>

あえて実装しなかったもの

新たに言語を追加しても、自動で認識するような設計にはしませんでした
ソースとしてのわかりやすさを優先するため
やろうと思えばできると思うけど、数行処理を追加するだけの手間と天秤にかけて
自動にするための実装コストのほうが高そうなので、個人的にはおすすめできないと思います

参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1