country name indo version
This commit is contained in:
@@ -10,7 +10,13 @@ Filtering Order:
|
||||
5. Filter indicators with consistent presence across FIXED countries
|
||||
6. Save analytical table (dengan nama/label lengkap untuk Looker Studio)
|
||||
|
||||
ADDED: Kolom indicator_name_id dan pillar_name_id (terjemahan Bahasa Indonesia)
|
||||
ADDED:
|
||||
- Kolom indicator_name_id dan pillar_name_id (terjemahan Bahasa Indonesia)
|
||||
- Kolom country_name_id (terjemahan Bahasa Indonesia nama negara)
|
||||
|
||||
FIXED:
|
||||
- Nama pilar "Access" -> "Akses" (konsisten di semua mapping)
|
||||
- Nama negara ASEAN dalam Bahasa Indonesia
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
@@ -40,21 +46,39 @@ from google.cloud import bigquery
|
||||
# TRANSLATION DICTIONARIES
|
||||
# =============================================================================
|
||||
|
||||
COUNTRY_NAME_ID_MAP: dict = {
|
||||
# Nama resmi -> Bahasa Indonesia
|
||||
"Brunei Darussalam" : "Brunei Darussalam",
|
||||
"Cambodia" : "Kamboja",
|
||||
"Indonesia" : "Indonesia",
|
||||
"Lao People's Democratic Republic" : "Laos",
|
||||
"Lao PDR" : "Laos",
|
||||
"Malaysia" : "Malaysia",
|
||||
"Myanmar" : "Myanmar",
|
||||
"Philippines" : "Filipina",
|
||||
"Singapore" : "Singapura",
|
||||
"Thailand" : "Thailand",
|
||||
"Timor-Leste" : "Timor-Leste",
|
||||
"Viet Nam" : "Vietnam",
|
||||
"Vietnam" : "Vietnam",
|
||||
}
|
||||
|
||||
PILLAR_TRANSLATION_ID: dict = {
|
||||
# 4 pilar utama Food Security
|
||||
"Availability" : "Ketersediaan",
|
||||
"Access" : "Keterjangkauan",
|
||||
"Utilization" : "Pemanfaatan",
|
||||
"Stability" : "Stabilitas",
|
||||
"Sustainability": "Keberlanjutan",
|
||||
# Variasi penulisan yang mungkin muncul
|
||||
"availability" : "Ketersediaan",
|
||||
"access" : "Keterjangkauan",
|
||||
"utilization" : "Pemanfaatan",
|
||||
"stability" : "Stabilitas",
|
||||
"sustainability": "Keberlanjutan",
|
||||
# 4 pilar utama Food Security — "Access" -> "Akses" (FIXED, bukan "Keterjangkauan")
|
||||
"Availability" : "Ketersediaan",
|
||||
"Access" : "Akses",
|
||||
"Utilization" : "Pemanfaatan",
|
||||
"Stability" : "Stabilitas",
|
||||
"Sustainability" : "Keberlanjutan",
|
||||
# Variasi penulisan huruf kecil
|
||||
"availability" : "Ketersediaan",
|
||||
"access" : "Akses",
|
||||
"utilization" : "Pemanfaatan",
|
||||
"stability" : "Stabilitas",
|
||||
"sustainability" : "Keberlanjutan",
|
||||
# Variasi dengan prefix "Food"
|
||||
"Food Availability" : "Ketersediaan Pangan",
|
||||
"Food Access" : "Keterjangkauan Pangan",
|
||||
"Food Access" : "Akses Pangan",
|
||||
"Food Utilization" : "Pemanfaatan Pangan",
|
||||
"Food Stability" : "Stabilitas Pangan",
|
||||
"Food Sustainability": "Keberlanjutan Pangan",
|
||||
@@ -195,6 +219,13 @@ INDICATOR_TRANSLATION_ID: dict = {
|
||||
}
|
||||
|
||||
|
||||
def translate_country(name: str) -> str:
|
||||
"""Terjemahkan nama negara ke Bahasa Indonesia. Fallback ke nama asli."""
|
||||
if not name:
|
||||
return name
|
||||
return COUNTRY_NAME_ID_MAP.get(name.strip(), name)
|
||||
|
||||
|
||||
def translate_indicator(name: str) -> str:
|
||||
"""Terjemahkan nama indikator ke Bahasa Indonesia. Fallback ke nama asli."""
|
||||
if not name:
|
||||
@@ -226,6 +257,7 @@ class AnalyticalLayerLoader:
|
||||
Output: fact_asean_food_security_selected -> DW layer (Gold) -> fs_asean_gold
|
||||
|
||||
Kolom tambahan:
|
||||
- country_name_id : terjemahan Bahasa Indonesia dari country_name
|
||||
- indicator_name_id : terjemahan Bahasa Indonesia dari indicator_name
|
||||
- pillar_name_id : terjemahan Bahasa Indonesia dari pillar_name
|
||||
"""
|
||||
@@ -625,12 +657,24 @@ class AnalyticalLayerLoader:
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# TAMBAHAN: kolom terjemahan Bahasa Indonesia
|
||||
# country_name_id : terjemahan Bahasa Indonesia dari country_name [BARU]
|
||||
# indicator_name_id : terjemahan Bahasa Indonesia dari indicator_name
|
||||
# pillar_name_id : terjemahan Bahasa Indonesia dari pillar_name
|
||||
# ------------------------------------------------------------------
|
||||
analytical_df['country_name_id'] = analytical_df['country_name'].apply(translate_country)
|
||||
analytical_df['indicator_name_id'] = analytical_df['indicator_name'].apply(translate_indicator)
|
||||
analytical_df['pillar_name_id'] = analytical_df['pillar_name'].apply(translate_pillar)
|
||||
|
||||
# Log negara yang belum punya terjemahan
|
||||
no_trans_ctr = analytical_df[
|
||||
analytical_df['country_name_id'] == analytical_df['country_name']
|
||||
]['country_name'].unique()
|
||||
if len(no_trans_ctr) > 0:
|
||||
self.logger.warning(
|
||||
f" [TRANSLATION] {len(no_trans_ctr)} country/countries tidak ada di kamus "
|
||||
f"(menggunakan nama asli): {list(no_trans_ctr)}"
|
||||
)
|
||||
|
||||
# Log indikator yang belum punya terjemahan (fallback ke nama asli)
|
||||
no_trans_ind = analytical_df[
|
||||
analytical_df['indicator_name_id'] == analytical_df['indicator_name']
|
||||
@@ -657,6 +701,7 @@ class AnalyticalLayerLoader:
|
||||
# Pastikan tipe data konsisten
|
||||
analytical_df['country_id'] = analytical_df['country_id'].astype(int)
|
||||
analytical_df['country_name'] = analytical_df['country_name'].astype(str)
|
||||
analytical_df['country_name_id'] = analytical_df['country_name_id'].astype(str)
|
||||
analytical_df['indicator_id'] = analytical_df['indicator_id'].astype(int)
|
||||
analytical_df['indicator_name'] = analytical_df['indicator_name'].astype(str)
|
||||
analytical_df['indicator_name_id'] = analytical_df['indicator_name_id'].astype(str)
|
||||
@@ -671,10 +716,21 @@ class AnalyticalLayerLoader:
|
||||
self.logger.info(f" Kolom yang disimpan: {list(analytical_df.columns)}")
|
||||
self.logger.info(f" Total rows: {len(analytical_df):,}")
|
||||
|
||||
# Log sample terjemahan negara
|
||||
sample_ctr = (
|
||||
analytical_df[['country_name', 'country_name_id']]
|
||||
.drop_duplicates()
|
||||
.sort_values('country_name')
|
||||
)
|
||||
self.logger.info("\n Terjemahan nama negara (EN -> ID):")
|
||||
for _, r in sample_ctr.iterrows():
|
||||
self.logger.info(f" {r['country_name']:<35} -> {r['country_name_id']}")
|
||||
|
||||
# Schema BigQuery
|
||||
schema = [
|
||||
bigquery.SchemaField("country_id", "INTEGER", mode="REQUIRED"),
|
||||
bigquery.SchemaField("country_name", "STRING", mode="REQUIRED"),
|
||||
bigquery.SchemaField("country_name_id", "STRING", mode="REQUIRED"),
|
||||
bigquery.SchemaField("indicator_id", "INTEGER", mode="REQUIRED"),
|
||||
bigquery.SchemaField("indicator_name", "STRING", mode="REQUIRED"),
|
||||
bigquery.SchemaField("indicator_name_id", "STRING", mode="REQUIRED"),
|
||||
@@ -710,7 +766,8 @@ class AnalyticalLayerLoader:
|
||||
'fixed_countries': len(self.selected_country_ids),
|
||||
'no_gaps' : True,
|
||||
'layer' : 'gold',
|
||||
'columns' : 'id + name + name_id (Looker Studio ready)'
|
||||
'columns' : 'id + name + name_id (Looker Studio ready)',
|
||||
'added_columns' : ['country_name_id', 'indicator_name_id', 'pillar_name_id'],
|
||||
}),
|
||||
'validation_metrics' : json.dumps({
|
||||
'fixed_countries' : len(self.selected_country_ids),
|
||||
|
||||
Reference in New Issue
Block a user